【学习笔记】 多线程资源管理器(附流程图附源码)
《奇怪的大冒险》教程视频连接:
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 }