AssetBundle的加载和卸载

    直接就开门见山了,Unity提供了很多AB包的加载的接口。

  1. AssetBundle.LoadFromFile :从本地加载 AssetBundle 资源包
  2. AssetBundle.LoadFromFileAsync :异步从本地加载 AssetBundle 资源包
  3. AssetBundle.LoadFromMemory :从缓存中下载
  4. AssetBundle.LoadFromMemoryAsync :异步从缓存中加载
private void LoadABFile() // 普通加载
        {
            string path = "../AssetBundles/prefab.yn";

            AssetBundle pre = AssetBundle.LoadFromFile(path);

            GameObject obj = pre.LoadAsset<GameObject>("Sphere");
            Instantiate(obj);
        }

        private void LoadMemoryABFile() // 缓存中加载
        {
            string path = "../AssetBundles/prefab.yn";

            AssetBundle pre = AssetBundle.LoadFromMemory(File.ReadAllBytes(path)); //因为要从缓存中取得,所以需要先加载到缓存
            LoadRelyABFile("prefab.yn");

            GameObject obj = pre.LoadAsset<GameObject>("Sphere");
            Instantiate(obj);
        }

        IEnumerator LoadABFileAsync() // 异步 普通加载
        {
            string path = "../AssetBundles/prefab.yn";

            AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);

            yield return request;

            AssetBundle pre = request.assetBundle;

            GameObject obj = pre.LoadAsset<GameObject>("Sphere");
            Instantiate(obj);
        }    

        IEnumerator LoadMemoryABFileAsync() // 异步从 缓存中加载
        {
            string path = "../AssetBundles/prefab.yn";

            AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path)); //因为要从缓存中取得,所以需要先加载到缓存

            yield return request; // 等待加载完成
            LoadRelyABFile("prefab.yn");

            AssetBundle pre = request.assetBundle;

            GameObject obj = pre.LoadAsset<GameObject>("Sphere");
            Instantiate(obj);
        }

因为异步的加载需要等待线程的返回,所以我们会采用携程去加载,并且等待返回。

下图是我们加载得到的内容

unity 异步加载资源回调 unity 异步加载ab包_unity3d

可以看出,这个球体缺少了材质,因为我在前面有说到:AB包之间互相是有依赖关系的 

那我们就了了解一下AB包的依赖关系。

 

AssetBundle的依赖关系

   网上找到一张很适合解释依赖关系的图:

unity 异步加载资源回调 unity 异步加载ab包_unity 异步加载资源回调_02

 上面的图我们可以看出

当我们需要加载一个AB包的时候,他可能会依赖着其他的一个或者多个资源包,而其他的资源包又可能依赖其他的别的包,形成了上图一样的数据结构,形象点说就是:

预制体 依赖 材质球 ;材质球 依赖 Shader和图片;

这样就是一个简单的一个依赖关系。了解了依赖关系之后,我们就可以去加载依赖包了

1.自己知道依赖关系,手动去加载包(方法简单粗暴,但是有点蠢);

2.通过Manifest文件查询到包依赖的其他包,一次加载出来;上面的图可以看出,所有的AB包都有一个共有的初始包,也就是AssetBundle这个包,他记录了所有的包的包名和依赖,Dependencies这个数组就是依赖的资源包

unity 异步加载资源回调 unity 异步加载ab包_缓存_03

接下来用代码去读取加载:

private void LoadRelyABFile(string abName) //加载依赖项目
        {
            string path = "../AssetBundles/";  // 如果是远程,就把这个路径改掉就好

            AssetBundle AB = AssetBundle.LoadFromFile(path + "AssetBundles");
            AssetBundleManifest manifest = AB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

            string[] relys = manifest.GetAllDependencies(abName);

            for (int i = 0; i < relys.Length; i++)
            {
                AssetBundle.LoadFromFile(path + relys[i]);
            }
        }

abName : 需要读取的AB包的名字;

加载完预制之后,我们再去加载预制所依赖的资源包,这样我们就可以完整展示出这个预制了

unity 异步加载资源回调 unity 异步加载ab包_unity 异步加载资源回调_04

 

AssetBundle的卸载

AB包每一次被加载都会在内存中开辟出一个空间,如果不卸载的话会导致内存越来越大,直到崩溃。所以我们在加载了AB包之后也要及时卸载AB包,释放出占用的内存。

AB包的卸载也是一个最容易出问题的地方,随意释放,会导致还存在依赖关系的资源立刻丢失,所以在卸载的时候一定要注意这个包没有被其他包或者其他的物体依赖。

卸载的接口

    1. AssetBundle.Unload(true); //卸载这个包的所有资源,包含其中正被使用的资源(只有实例出来的包可以调用这个接口)
    2. AssetBundle.Unload(false);// 卸载这个包没被使用的资源 (未被卸载的资源会失去AB的标记,无法再通过卸载AB的方式释放)
    3. AssetBundle.UnloadAllAssetBundles(false); // 释放所有未使用的资源,容易造成内存泄漏(未被卸载的资源会失去AB的标记,无法再通过卸载AB的方式释放)
    4. AssetBundle.UnloadAllAssetBundles(true); //完全卸载,会把实例出来的对象也一起灭掉了
    5. 当切换场景的时候,系统会默认调用一次AssetBundle.UnloadAllAssetBundles(true)这个方法。