【学习笔记】 多线程资源管理器(附流程图附源码)

《奇怪的大冒险》教程视频连接:
http://www.taikr.com/course/222
笔记结合了前7课的视频内容,感谢新总提供的免费视频
PS:部分字段、属性和方法的命名与视频教程中有出入。

资源管理器核心的集合一共有三个:1.等待加载的资源队列

private Queue <ResLoadRequest> m_QueWaitLoadAsset = new Queue< ResLoadRequest >();

2.当前正在加载的资源列表

private List <ResLoadRequest> m_LstLoadingAsset = new List< ResLoadRequest >();

3.已经完成加载的资源字典

private Dictionary <string, AssetPack > m_DicLoadedAsset = new Dictionary< string , AssetPack >();

资源管理器的核心思想就是通过操作这三个集合,进行资源的加载,持有及释放。

三个集合的类型,可以看到明显的差异。

集合 <等待加载> 和 <正在加载> 的元素类型均为 ResLoadRequest类(资源加载数据类)

集合 <完成加载> 的元素类型为 AssetPack类(资源包类)

先从几个集合的转换,做个简要介绍

然后是资源管理器的流程图:

框架层级的东西,单纯看代码比较难以理解,所以我比较喜欢画图记忆,大体原理掌握了,自己也可以写出来了~!

在这基础上还可以增加AssetBundle的资源管理器。

另附本次学习的资源管理器代码

  1 // **********************************************************************
  2 //
  3 // 文件名(File Name):             ResMgr.cs
  4 //
  5 // 作者(Author):                 沐小沫
  6 //
  7 // 日期(Create Date):             2015-07-10
  8 //
  9 // **********************************************************************
 10
 11 using UnityEngine;
 12 using System.Collections;
 13 using System;
 14 using System.Collections.Generic;
 15 using UnityEngine.EventSystems;
 16
 17 public class ResMgr : MonoBehaviour
 18 {
 19     private static ResMgr m_Instance = null;                // 静态实例
 20     /// <summary>
 21     /// 获取静态实例
 22     /// </summary>
 23     /// <returns>静态实例</returns>
 24     public static ResMgr GetInstance()
 25     {
 26         return m_Instance;
 27     }
 28
 29     private GameObject m_CachedGameObject;                  // 缓存对象
 30     private GameObject CachedGameObject
 31     {
 32         get
 33         {
 34             if (null == m_CachedGameObject && null != m_Instance)
 35             {
 36                 m_CachedGameObject = this.gameObject;
 37             }
 38
 39             return m_CachedGameObject;
 40         }
 41     }
 42
 43     private static int m_ProcessorCount = 0;                // 线程数量
 44     private static int ProcessorCount
 45     {
 46         set { m_ProcessorCount = Mathf.Clamp(value, 1, 8); }
 47         get { return m_ProcessorCount; }
 48     }
 49
 50     void Awake()
 51     {
 52         ProcessorCount = SystemInfo.processorCount;
 53         DontDestroyOnLoad(CachedGameObject);
 54         m_Instance = this;
 55     }
 56
 57     /// <summary>
 58     /// 当前正在加载的资源列表
 59     /// </summary>
 60     private List<ResLoadRequest> m_LstLoadingAsset = new List<ResLoadRequest>();
 61
 62     /// <summary>
 63     /// 等待加载的资源队列
 64     /// </summary>
 65     private Queue<ResLoadRequest> m_QueWaitLoadAsset = new Queue<ResLoadRequest>();
 66
 67     /// <summary>
 68     /// 已经完成加载的资源字典
 69     /// </summary>
 70     private Dictionary<string, AssetPack> m_DicLoadedAsset = new Dictionary<string, AssetPack>();
 71
 72
 73     /// <summary>
 74     /// 从Resources中加载一个资源
 75     /// </summary>
 76     /// <param name="assetName">资源名称</param>
 77     /// <param name="assetType">资源类型</param>
 78     /// <param name="loadListeners">加载完成的监听接口</param>
 79     /// <param name="isKeepInMemory">是否常驻内存</param>
 80     public void LoadAsset(string assetName, ILoadListeners loadListeners, Type assetType = null, bool isKeepInMemory = false)
 81     {
 82         if(string.IsNullOrEmpty(assetName))
 83         {
 84             if (null != loadListeners)
 85             {
 86                 loadListeners.Failure();
 87             }
 88             return;
 89         }
 90
 91         if (m_DicLoadedAsset.ContainsKey(assetName))
 92         {
 93             if (null != loadListeners)
 94             {
 95                 loadListeners.Success(m_DicLoadedAsset[assetName].m_Asset);
 96             }
 97             return;
 98         }
 99
100         for (int i = 0; i < m_LstLoadingAsset.Count; i++)
101         {
102             ResLoadRequest request = m_LstLoadingAsset[i];
103             if (request.m_AssetName.Equals(assetName))
104             {
105                 request.AddListeners(loadListeners);
106                 return;
107             }
108         }
109
110         foreach (ResLoadRequest request in m_QueWaitLoadAsset)
111         {
112             if (request.m_AssetName.Equals(assetName))
113             {
114                 request.AddListeners(loadListeners);
115                 return;
116             }
117         }
118
119         ResLoadRequest loadRequest = new ResLoadRequest(assetName, isKeepInMemory, assetType);
120         loadRequest.AddListeners(loadListeners);
121         m_QueWaitLoadAsset.Enqueue(loadRequest);
122     }
123
124     /// <summary>
125     /// 从资源队列中处理待加载的资源
126     /// </summary>
127     public void Update()
128     {
129         if(m_LstLoadingAsset.Count > 0)
130         {
131             for(int i = m_LstLoadingAsset.Count - 1; i >= 0 ; i--)
132             {
133                 if (m_LstLoadingAsset[i].IsLoadedDone)
134                 {
135                     LoadAssetFinish(m_LstLoadingAsset[i]);
136                     m_LstLoadingAsset.RemoveAt(i);
137                 }
138             }
139         }
140
141         while (m_LstLoadingAsset.Count < ProcessorCount && m_QueWaitLoadAsset.Count > 0)
142         {
143             ResLoadRequest request = m_QueWaitLoadAsset.Dequeue();
144             m_LstLoadingAsset.Add(request);
145             request.LoadAsync();
146         }
147     }
148
149     /// <summary>
150     /// 资源加载完毕
151     /// </summary>
152     void LoadAssetFinish(ResLoadRequest request)
153     {
154         if(null != request)
155         {
156             for (int i = 0; i < request.m_LstListeners.Count; i++)
157             {
158                 ILoadListeners listeners = request.m_LstListeners[i];
159
160                 if (null != listeners)
161                 {
162                     if (null != request.m_Request && null != request.Asset)
163                     {
164                         listeners.Success(request.Asset);
165
166                         AssetPack pack = new AssetPack(request.m_AssetType, request.m_IsKeepInMemory);
167                         pack.m_Asset = request.Asset;
168                         m_DicLoadedAsset.Add(request.m_AssetName, pack);
169                     }
170                     else
171                     {
172                         listeners.Failure();
173                     }
174                 }
175             }
176
177         }
178     }
179
180     /// <summary>
181     /// 释放指定的资源
182     /// </summary>
183     /// <param name="assetName">资源名字</param>
184     /// <param name="canRealseKeepInMemory">是否可以释放常驻内存的资源</param>
185     public void ReleaseAsset(string assetName, bool canRealseKeepInMemory)
186     {
187         if (!m_DicLoadedAsset.ContainsKey(assetName))
188         {
189             return;
190         }
191
192         if (m_DicLoadedAsset[assetName].m_IsKeepInMemory && !canRealseKeepInMemory)
193         {
194             return;
195         }
196
197         m_DicLoadedAsset[assetName] = null;
198         m_DicLoadedAsset.Remove(assetName);
199
200         Resources.UnloadUnusedAssets();
201     }
202
203     /// <summary>
204     /// 释放全部资源
205     /// </summary>
206     public void ReleaseAllAsset()
207     {
208         foreach (KeyValuePair<string, AssetPack> pair in m_DicLoadedAsset)
209         {
210             m_DicLoadedAsset[pair.Key] = null;
211         }
212
213         m_DicLoadedAsset.Clear();
214         Resources.UnloadUnusedAssets();
215     }
216
217 #region 资源加载数据类
218     /// <summary>
219     /// 加载类
220     /// </summary>
221     public class ResLoadRequest
222     {
223         /// <summary>
224         /// 资源名称
225         /// </summary>
226         public string m_AssetName;
227
228         /// <summary>
229         /// 资源类型
230         /// </summary>
231         public Type m_AssetType;
232
233         /// <summary>
234         /// 监听接口
235         /// </summary>
236         public List<ILoadListeners> m_LstListeners = new List<ILoadListeners>();
237
238         /// <summary>
239         /// 加载资源请求
240         /// </summary>
241         public ResourceRequest m_Request;
242
243         /// <summary>
244         /// 是否常驻内存
245         /// </summary>
246         public bool m_IsKeepInMemory;
247
248         /// <summary>
249         /// 重载构造函数
250         /// </summary>
251         /// <param name="assetName">资源名称</param>
252         /// <param name="isKeepInMemory">是否常驻内存</param>
253         /// <param name="assetType">资源类型</param>
254         public ResLoadRequest(string assetName, bool isKeepInMemory, Type assetType)
255         {
256             this.m_AssetName = assetName;
257             this.m_IsKeepInMemory = isKeepInMemory;
258             this.m_AssetType = assetType;
259         }
260
261         /// <summary>
262         /// 添加一个监听到监听列表
263         /// </summary>
264         /// <param name="listeners">监听接口</param>
265         public void AddListeners(ILoadListeners listeners)
266         {
267             if (listeners == null)
268             {
269                 return;
270             }
271
272             if(!m_LstListeners.Contains(listeners))
273             {
274                 m_LstListeners.Add(listeners);
275             }
276         }
277
278         /// <summary>
279         /// 加载到的资源
280         /// </summary>
281         public UnityEngine.Object Asset
282         {
283             get
284             {
285                 if (null != m_Request && null != m_Request.asset)
286                 {
287                     return m_Request.asset;
288                 }
289                 else
290                 {
291                     return null;
292                 }
293             }
294         }
295
296         /// <summary>
297         /// 当前是否已经加载完成
298         /// </summary>
299         public bool IsLoadedDone
300         {
301             get { return (null != m_Request && m_Request.isDone); }
302         }
303
304         /// <summary>
305         /// 异步加载资源
306         /// </summary>
307         public void LoadAsync()
308         {
309             if (null == m_AssetType)
310             {
311                 m_AssetType = typeof(GameObject);
312             }
313
314             m_Request = Resources.LoadAsync(m_AssetName, m_AssetType);
315         }
316     }
317
318     /// <summary>
319     /// 资源包
320     /// </summary>
321     public class AssetPack
322     {
323         /// <summary>
324         /// 资源类型
325         /// </summary>
326         public Type m_AssetType;
327
328         /// <summary>
329         /// 是否常驻内存
330         /// </summary>
331         public bool m_IsKeepInMemory;
332
333         /// <summary>
334         /// 资源
335         /// </summary>
336         public UnityEngine.Object m_Asset;
337
338         public AssetPack(Type assetType, bool isKeepInMemory)
339         {
340             m_AssetType = assetType;
341             m_IsKeepInMemory = isKeepInMemory;
342         }
343     }
344 #endregion
345
346 #region 加载资源完成后监听接口
347
348     public interface ILoadListeners
349     {
350         /// <summary>
351         /// 加载成功
352         /// </summary>
353         /// <param name="asset">资源</param>
354         void Success(UnityEngine.Object asset);
355
356         /// <summary>
357         /// 加载失败
358         /// </summary>
359         void Failure();
360     }
361
362 #endregion
363 }
时间: 2024-10-29 00:40:25

【学习笔记】 多线程资源管理器(附流程图附源码)的相关文章

C++11学习笔记:std::move和std::forward源码分析

std::move和std::forward是C++0x中新增的标准库函数,分别用于实现移动语义和完美转发. 下面让我们分析一下这两个函数在gcc4.6中的具体实现. 预备知识 引用折叠规则: X& + & => X& X&& + & => X& X& + && => X& X&& + && => X&& 函数模板参数推导规则(右值引用参数部分):

hadoop学习笔记(四)——eclipse+maven+hadoop2.5.2源码

Eclipse中用maven导入hadoop源码 1)  安装并配置maven环境变量 M2_HOME: D:\profession\hadoop\apache-maven-3.3.3 PATH: %M2_HOME%\bin; 2)  验证:mvn –version 3)  下载protobuf-2.5.0.tar.gz 和 protoc-2.5.0-win32.zip 4)  将protoc-2.5.0-win32中的protoc.exe拷贝到c:\windows\system32中 5) 

IOS学习笔记 -- 多线程

多线程1.多线程的原理 1>.同一时间,CPU只能处理1条线程,只有1条线程在工作(执行) 2>.多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换) 3>.如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象如果线程非常非常多,会发生: 1>.CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源 2>.每条线程被调度执行的频次会降低(线程的执行效率降低) 2.多线程的优缺点 1>.多线程的优点 能适当提高程序的执行效率 能适当提高资源

java学习笔记13--比较器(Comparable、Comparator)

java学习笔记13--比较器(Comparable.Comparator) 分类: JAVA 2013-05-20 23:20 3296人阅读 评论(0) 收藏 举报 Comparable接口的作用 之前Arrays类中存在sort()方法,此方法可以直接对对象数组进行排序. Comparable接口 可以直接使用java.util.Arrays类进行数组的排序操作,但对象所在的类必须实现Comparable接口,用于指定排序接口. Comparable接口的定义如下: public  int

springmvc学习笔记(20)-拦截器

springmvc学习笔记(20)-拦截器 springmvc学习笔记20-拦截器 拦截定义 拦截器配置 针对HandlerMapping配置 类似全局的拦截器 拦截测试 拦截器应用实现登陆认证 需求 登陆controller方法 登陆认证拦截实现 本文主要介绍springmvc中的拦截器,包括拦截器定义和的配置,然后演示了一个链式拦截的测试示例,最后通过一个登录认证的例子展示了拦截器的应用 拦截定义 定义拦截器,实现HandlerInterceptor接口.接口中提供三个方法. public

Linux程序设计学习笔记----多线程编程线程同步机制之互斥量(锁)与读写锁

互斥锁通信机制 基本原理 互斥锁以排他方式防止共享数据被并发访问,互斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个互斥锁逻辑上绑定之后,对该资源的访问操作如下: (1)在访问该资源之前需要首先申请互斥锁,如果锁处于开状态,则申请得到锁并立即上锁(关),防止其他进程访问资源,如果锁处于关,则默认阻塞等待. (2)只有锁定该互斥锁的进程才能释放该互斥锁. 互斥量类型声明为pthread_mutex_t数据类型,在<bits/pthreadtypes.h>中有具体的定义. 互斥量

Linux程序设计学习笔记----多线程编程之线程同步之条件变量

转载请注明出处:http://blog.csdn.net/suool/article/details/38582521. 基本概念与原理 互斥锁能够解决资源的互斥访问,但是在某些情况下,互斥并不能解决问题,比如两个线程需 要互斥的处理各自的操作,但是一个线程的操作仅仅存在一种条件成立的情况下执行,一旦错过不可再重现,由于线程间相互争夺cpu资源,因此在条件成立的时候,该线程不一定争夺到cpu而错过,导致永远得不到执行..... 因此需要某个机制来解决此问题,更重要的是,线程仅仅只有一种情况需要执

JAVA学习笔记 -- 多线程之共享资源

在多线程程序运行过程中,可能会涉及到两个或者多个线程试图同时访问同一个资源.为了防止这种情况的发生,必须在线程使用共享资源时给资源"上锁",以阻挡其它线程的访问.而这种机制也常常被称为互斥量,本文主要介绍它的两种方式synchronized和Lock . 1.synchronized 当任务要执行被synchronized关键字保护的代码片段的时候,它会检查锁是否可用,然后获取锁,执行代码,释放锁.synchronized也有两种用法: A.synchronized方法 import

Linux程序设计学习笔记----多线程编程基础概念与基本操作

转载请注明出处,http://blog.csdn.net/suool/article/details/38542543,谢谢. 基本概念 线程和进程的对比 用户空间资源对比 每个进程在创建的时候都申请了新的内存空间以存储代码段\数据段\BSS段\堆\栈空间,并且这些的空间的初始化值是父进程空间的,父子进程在创建后不能互访资源. 而每个新创建的线程则仅仅申请了自己的栈,空间,与同进程的其他线程共享该进程的其他数据空间包括代码段\数据段\BSS段\堆以及打开的库,mmap映射的文件与共享的空间,使得