فهرست منبع

增加一个ResourcesLoaderComponent类,可以非常精细的控制资源的生命周期,用处举例
1. UI加载的ab包希望UI释放后将ab包释放,那么可以在UI上挂一个ResourcesLoaderComponent,该UI的资源都使用这个ResourcesLoaderComponent加载。ui释放的时候ResourcesLoaderComponent也释放了
2. UI加载的资源希望跟随场景释放,那么加载该UI的资源可以使用场景的ResourcesLoaderComponent去加载资源
3. UI的资源希望永远不释放,可以在ZoneScene上挂载一个ResourcesLoaderComponent

原则,永远不要直接使用ResourcesComponent去加载资源,而是使用ResourcesLoaderComponent,这样ab包资源将自带生命周期
获取ab包中的Object仍然使用ResourcesComponent来获取,ResourcesLoaderComponent仅仅是用来加载跟释放资源的

tanghai 4 سال پیش
والد
کامیت
cc79430c37

+ 1 - 0
Unity/Assets/Model/Module/CoroutineLock/CoroutineLockType.cs

@@ -9,6 +9,7 @@ namespace ET
         UnitId,                    // Map服务器上线下线时使用
         UnitId,                    // Map服务器上线下线时使用
         DB,
         DB,
         Resources,
         Resources,
+        ResourcesLoader,
 
 
         Max, // 这个必须在最后
         Max, // 这个必须在最后
     }
     }

+ 15 - 12
Unity/Assets/ModelView/Demo/Resource/ResourcesComponent.cs

@@ -184,7 +184,7 @@ namespace ET
 
 
         private string[] GetDependencies(string assetBundleName)
         private string[] GetDependencies(string assetBundleName)
         {
         {
-            string[] dependencies = new string[0];
+            string[] dependencies = Array.Empty<string>();
             if (DependenciesCache.TryGetValue(assetBundleName, out dependencies))
             if (DependenciesCache.TryGetValue(assetBundleName, out dependencies))
             {
             {
                 return dependencies;
                 return dependencies;
@@ -276,22 +276,25 @@ namespace ET
 
 
             return resource;
             return resource;
         }
         }
-
-        public async ETTask UnloadBundles(List<string> bundleList, bool unload = true)
+        
+        // 一帧卸载一个包,避免卡死
+        public async ETTask UnloadBundleAsync(string assetBundleName, bool unload = true)
         {
         {
-            int i = 0;
-            foreach (string bundle in bundleList)
+            assetBundleName = assetBundleName.BundleNameToLower();
+
+            string[] dependencies = GetSortedDependencies(assetBundleName);
+
+            //Log.Debug($"-----------dep unload start {assetBundleName} dep: {dependencies.ToList().ListToString()}");
+            foreach (string dependency in dependencies)
             {
             {
-                using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Resources, bundle.GetHashCode()))
+                using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.Resources, assetBundleName.GetHashCode()))
                 {
                 {
-                    if (++i % 5 == 0)
-                    {
-                        await TimerComponent.Instance.WaitFrameAsync();
-                    }
-
-                    this.UnloadBundle(bundle, unload);
+                    this.UnloadOneBundle(dependency, unload);
+                    
+                    await TimerComponent.Instance.WaitFrameAsync();
                 }
                 }
             }
             }
+            //Log.Debug($"-----------dep unload finish {assetBundleName} dep: {dependencies.ToList().ListToString()}");
         }
         }
 
 
         // 只允许场景设置unload为false
         // 只允许场景设置unload为false

+ 62 - 0
Unity/Assets/ModelView/Demo/Resource/ResourcesLoaderComponent.cs

@@ -0,0 +1,62 @@
+using System.Collections.Generic;
+
+namespace ET
+{
+    [ObjectSystem]
+    public class ResourcesLoaderComponentDestroySystem: DestroySystem<ResourcesLoaderComponent>
+    {
+        public override void Destroy(ResourcesLoaderComponent self)
+        {
+            async ETTask UnLoadAsync()
+            {
+                using ListComponent<string> list = ListComponent<string>.Create();
+            
+                list.List.AddRange(self.LoadedResource);
+                self.LoadedResource = null;
+            
+                // 延迟5秒卸载包,因为包卸载是引用技术,5秒之内假如重新有逻辑加载了这个包,那么可以避免一次卸载跟加载
+                await TimerComponent.Instance.WaitAsync(5000);
+                
+                foreach (string abName in list.List)
+                {
+                    using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.ResourcesLoader, abName.GetHashCode(), 0))
+                    {
+                        if (ResourcesComponent.Instance == null)
+                        {
+                            return;
+                        }
+                        await ResourcesComponent.Instance.UnloadBundleAsync(abName);
+                    }
+                }
+            }
+            
+            
+            UnLoadAsync().Coroutine();
+        }
+    }
+
+    public class ResourcesLoaderComponent: Entity
+    {
+        public HashSet<string> LoadedResource = new HashSet<string>();
+
+        public async ETTask LoadAsync(string ab)
+        {
+            using (await CoroutineLockComponent.Instance.Wait(CoroutineLockType.ResourcesLoader, ab.GetHashCode(), 0))
+            {
+                if (this.IsDisposed)
+                {
+                    Log.Error($"resourceload already disposed {ab}");
+                    return;
+                }
+                
+                if (this.LoadedResource.Contains(ab))
+                {
+                    return;
+                }
+                
+                LoadedResource.Add(ab);
+                await ResourcesComponent.Instance.LoadBundleAsync(ab);
+            }
+        }
+    }
+}