Version: 2023.2
Customizing the Asset Database workflow
Special folder names

AssetDatabase 批处理

使用批处理可以减少在代码中更改资源时所需的时间和处理量。

如果在代码中对多个资源进行更改(例如,复制或移动资源文件),则资源数据库 (Asset Database) 的默认行为是依次处理每个更改,并对资源执行完整的“刷新”过程,然后再转到下一行代码。

以下示例中将更改三个资源。执行的操作是复制 Asset1、移动 Asset2 和删除 Asset3:

AssetDatabase.CopyAsset("Assets/Asset1.txt", "Assets/Text/Asset1.txt");
AssetDatabase.MoveAsset("Assets/Asset2.txt", "Assets/Text/Asset2.txt");
AssetDatabase.DeleteAsset("Assets/Asset3.txt");

如果不进行批处理,Unity 会在处理每个更改后移到下一行代码。这不仅会花费不必要的时间,还会触发许多回调(如果使用批处理的话,则可以避免)。

另一种替代做法是可以指定资源数据库应该一次性处理一组操作。为此,需要告诉资源数据库在您进行更改之前暂停其正常行为,然后在您更改完成后告诉它恢复。

具体而言,如果您要执行以下任意多项操作,则应尝试使用批处理:

  • AssetDatabase.ImportAsset
  • AssetDatabase.MoveAsset
  • AssetDatabase.CopyAsset
  • AddObjectToAsset

处理操作的方法

要指定资源数据库应该一次性处理一组操作,可以使用以下方法:AssetDatabase.StartAssetEditingAssetDatabase.StopAssetEditing

AssetDatabase.StartAssetEditing

此方法告诉资源数据库您正在开始对资源进行编辑。资源数据库进入暂停状态,并在您调用相应的 StopAssetEditing 方法告诉您已完成之前,不会对资源进行任何进一步的更改。

AssetDatabase.StopAssetEditing

完成所有的资源更改后,请调用此方法告诉资源数据库处理您的更改并恢复其立即自动处理更改的正常行为。然后,资源数据库以批处理方式处理您在 StartAssetEditingStopAssetEditing 之间进行的更改,这种处理方法比逐个处理的速度要快。

嵌套调用 StartAssetEditing 和 StopAssetEditing

如果您对 StartAssetEditing 进行了多次调用,必须对 StopAssetEditing 进行相应次数的调用,使资源数据库恢复其自动处理更改的正常行为。

这是因为这些函数会递增和递减计数器,而不是充当简单的开/关功能。调用 StartAssetEditing 将递增计数器,而调用 StopAssetEditing 将递减计数器。当计数器达到零时,资源数据库将恢复其正常行为。

Unity 使用计数器而不是简单开/关布尔值的原因是,通过使用计数器,如果您的代码执行多个嵌套的“start”和“stop”对,内部对不会意外地过早恢复资源数据库的正常行为。相反,每对会将计数器加一或减一,并且如果您的代码正确嵌套,则对 StopAssetEditing 的最终外部调用会将计数器设置为零。

注意:您的代码绝不应该使计数器降到零以下。这样做会产生错误。

示例

以下示例显示了这些方法的推荐使用方式:

using UnityEditor;
public class StartStopAssetEditingExample : MonoBehaviour
{
    [MenuItem("APIExamples/StartStopAssetEditing")]
    static void CallAssetDatabaseAPIsBetweenStartStopAssetEditing()
    {
        try
        {
            //将资源数据库置于大多数 API
            //都暂停导入的状态
            AssetDatabase.StartAssetEditing();
            AssetDatabase.CopyAsset("Assets/Asset1.txt", "Assets/Text/Asset1.txt");
            AssetDatabase.MoveAsset("Assets/Asset2.txt", "Assets/Text/Asset2.txt");
            AssetDatabase.DeleteAsset("Assets/Asset3.txt");
        }
        finally
        {
            //在 "finally" 代码块中添加
            //对 StopAssetEditing 的调用可确保
            //在离开此函数时重置 AssetDatabase 状态
            AssetDatabase.StopAssetEditing();
        }
    }
}

使用 try…finally 进行资源编辑

调用 AssetDatabase.StartAssetEditing 时,Unity 会将整个 Editor 的 AssetDatabase 置于暂停状态。因此,如果您没有对 AssetDatabase.StopAssetEditing 进行相应的调用,则在涉及任何与资源相关的操作(导入、刷新等)时,Editor 会看起来无响应,并需要重新启动 Editor 以恢复其正常运行状态。

不使用 tryfinally 代码块时,如果任何用于修改资源的代码导致了错误,则可能会阻止调用 StopAssetEditing。为了避免这种情况,请将这些调用与 StartAssetEditing 一起包裹在一个 tryfinally 代码块中,然后将资源修改代码包含在 try 代码块中,而将 StopAssetEditing 调用放在 finally 代码块中。这样可以确保,如果在 try 代码块中进行更改时发生了任何异常,仍可以保证将会调用 AssetDatabase.StopAssetEditing

Customizing the Asset Database workflow
Special folder names