AddressableAsset源码学习:组成与工作原理
阅前提示
该系列为Unity AddressableAssetSystem 学习笔记,记录源码阅读的理解。
适合人群:All
阅读方式:浏览
如描述有误请指教,如果对你有所帮助,点赞收藏吧:)
文章目录
- 阅前提示
- 简介
- 组成
- 生命周期
- 资源加载的本质
- 工作流程
官方文档
简介
Addressable Asset system 是Unity推出的新的资产管理加载打包的插件。它主打的特点在于:便捷
相较于传统的资产加载方式(Resources/AssetBundle),AddressableAssest拥有了完备的可视化编辑窗口以及内存管理。
- VS Resources:不需要对资产路径要求的那么严格,做到了任何地方都可能加载。
- VS AssetBundle:不需要复杂的准备过程,开发即用,并且不需要单独的进行内存管理,总结下来就是比较无脑。
其他关于Addressable的基础介绍这里就不再赘述了,作者在写这篇文章之前浏览了网上其他有关AddressableAsset的文章,发现存在很多关于此的基础介绍和简单使用,所以这里就不提了。接下来我们就从源码出发,好好看看AddressableAsset。
组成
Addressable Asset System,我把它的组成分为以下几个部分:
- Manager
- AddressablesImpl :AddressableAsset使用的接口本口
- ResourceManager:管理资源
- Operation
- AsyncOperation :Addressable 核心异步操作流,一切的加载都源于其异步链式操作(AsyncOperation + ChainOperation)
- ProviderOperation:资源加载操作,异步操作真正执行者,实现资源的异步加载。
- Locator
- ResourceLocationBase:资产定位的组成部分
这三个部分就包含了整个系统的所有脚本了,这里只列举了具有代表性的部分脚本,以便大家找到阅读源码的位置。
简单的来说,Addressable Asset System 的优势在于它统一了资源加载的入口与资源加载的方式。
可想而知,在使用Resources或者AssetBundle时我们关心的地方在哪?我们希望加载资源的Key是一致的,不希望它在情况A的时候要使用KeyA来加载,情况B的时候使用KeyB来加载,这很烦不利于资源的管理。
我们还要考虑加载方式,是同步加载还是异步加载。Addressable 全都给你省了~
生命周期
初始化:
public AsyncOperationHandle<IResourceLocator> InitializeAsync(string runtimeDataPath, string providerSuffix = null, bool autoReleaseHandle = true)
m_InitializationOperation:初始化的异步操作处理
添加各类Provider:ResourceManager.ResourceProviders.Add(...)
Update:
internal void Update(float unscaledDeltaTime)
资源加载的本质
private AsyncOperationHandle ProvideResource(IResourceLocation location, Type desiredType = null){if (location == null)throw new ArgumentNullException("location");IResourceProvider provider = null;if (desiredType == null){provider = GetResourceProvider(desiredType, location);if (provider == null)return CreateCompletedOperation<object>(null, new UnknownResourceProviderException(location).Message);desiredType = provider.GetDefaultType(location);}IAsyncOperation op;int hash = location.Hash(desiredType);if (m_AssetOperationCache.TryGetValue(hash, out op)){op.IncrementReferenceCount();return new AsyncOperationHandle(op);}Type provType;if (!m_ProviderOperationTypeCache.TryGetValue(desiredType, out provType))m_ProviderOperationTypeCache.Add(desiredType, provType = typeof(ProviderOperation<>).MakeGenericType(new Type[] { desiredType }));op = CreateOperation<IAsyncOperation>(provType, provType.GetHashCode(), hash, m_ReleaseOpCached);// Calculate the hash of the dependenciesint depHash = location.DependencyHashCode;var depOp = location.HasDependencies ? ProvideResourceGroupCached(location.Dependencies, depHash, null, null) : default(AsyncOperationHandle<IList<AsyncOperationHandle>>);if (provider == null)provider = GetResourceProvider(desiredType, location);((IGenericProviderOperation)op).Init(this, provider, location, depOp);var handle = StartOperation(op, depOp);if (depOp.IsValid())depOp.Release();return handle;}
核心就是这一部分,返回 AsyncOperationHandle 用于做异步逻辑的节点触发。资源由ResourceProviderBase来完成加载,AsyncOperationBase 为 Provider 与 Handle的桥梁
工作流程
1.key -> IResourceProvider : 唯一路径 对应 IResourceProvider
2. ProvideResource :IResourceProvider 生成 AsyncOperationHandle
private AsyncOperationHandle ProvideResource(IResourceLocation location, Type desiredType = null)
细节:
provider 是执行资源加载的真正位置(继承ResourceProviderBase):根据location 数据获取对应的provider
public IResourceProvider GetResourceProvider(Type t, IResourceLocation location)
op 是存放provider的操作流(ProviderOperation), 以 location.Hash为key -> m_AssetOperationCache
depOp 是依赖资源的加载操作
根据 location 获取等到 provider :
provider = GetResourceProvider(desiredType, location);
op init 时绑定 provider :
((IGenericProviderOperation)op).Init(this, provider, location, depOp);
链式操作 执行 op.Execute :
var handle = StartOperation(op, depOp);
op.Execute 时进行provider的资源加载,并将自身绑定在ProvideHandle中 :
m_Provider.Provide(new ProvideHandle(m_ResourceManager, this));
provider 资源加载完毕之后执行 ProvideHandle.Complete -> 即 op.ProviderCompleted :
InternalOp.ProviderCompleted<T>(result, status, exception);
result 就是加载的资源最终执行 AsyncOperationBase.Complete
3. StartOperation(operation,dependency) : 链式操作dependency若没完成则等待dependency结束
var handle = StartOperation(op, depOp);
internal void Start(ResourceManager rm, AsyncOperationHandle dependency, DelegateList<float> updateCallbacks){...if (dependency.IsValid() && !dependency.IsDone)dependency.Completed += m_dependencyCompleteAction;elseInvokeExecute();}
**4. InvokeExecute : 执行Execute() 并在ResourceManager帧更新中添加回调 **
ResourceManager.m_UpdateCallbacks.Add(AsyncOperationBase.UpdateCallback)
ResourceManager.m_UpdateCallbacks 基于 MonoBehaviourCallbackHooks
5.ProviderOperation.Execute
protected override void Execute(){...try{m_Provider.Provide(new ProvideHandle(m_ResourceManager, this));}catch (Exception e){ProviderCompleted(default(TObject), false, e);}}
执行各类Provider的Provide 进行资源加载,例如 AssetBundleProvider.Provide
m_RequestOperation = AssetBundle.LoadFromFileAsync(path, m_Options == null ? 0 : m_Options.Crc);
m_RequestOperation.completed += LocalRequestOperationCompleted;private void LocalRequestOperationCompleted(AsyncOperation op)
{m_AssetBundle = (op as AssetBundleCreateRequest).assetBundle;m_ProvideHandle.Complete(this, m_AssetBundle != null, null);
}InternalOp.ProviderCompleted<T>(result, status, exception);
.
.
.
.
.
嗨,我是作者Vin129,逐儿时之梦正在游戏制作的技术海洋中漂泊。知道的越多,不知道的也越多。希望我的文章对你有所帮助:)
AddressableAsset源码学习:组成与工作原理相关推荐
- 【Android 源码学习】SystemServer启动原理
Android 源码学习 SystemServer启动原理 望舒课堂 SystemServer进程启动原理学习记录整理. 参考文章: Android系统启动流程(三)解析SyetemServer进程启 ...
- spring源码学习之整合Mybatis原理分析
本文主要解析spring是如何与mybatis进行整合,整合的过程中需要哪些组件的支持.以前面提到过的配置例子<spring源码学习之aop事物标签解析> 整合的过程中需要使用以下这个依赖 ...
- 【Android 源码学习】Zygote启动原理
Android 源码学习 Zygote启动原理 望舒课堂 Zygote进程启动原理学习记录整理. Zygote简介 Zygote是进程在init进程启动时创建的,进程本身是app_process,来源 ...
- (转)spring源码解析,spring工作原理
转自:https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/ Spring 的骨骼架构 Spring 总共有十几个组件,但是 ...
- 从源码角度了解react工作原理
为什么要用虚拟dom DOM操作很慢,轻微的操作都可能导致⻚面重新排版,非常耗性能.相对于DOM对象(dom对象打印出来很大,很难diff),js对象 处理起来更快,而且更简单.通过diff算法对比新 ...
- 从源码角度分析 Mybatis 工作原理
作者:vivo互联网服务器团队-Zhang Peng 一.MyBatis 完整示例 这里,我将以一个入门级的示例来演示 MyBatis 是如何工作的. 注:本文后面章节中的原理.源码部分也将基于这个示 ...
- Go框架 gin 源码学习--路由的实现原理剖析
往期回顾: gin源码解析 - gin 与 net/http 的关系 gin 源码解析 - 详解http请求在gin中的流转过程 上面两篇文章基本讲清楚了 Web Server 如何接收客户端请求,以 ...
- 医学影像信息系统(PACS源码)基本概况和工作原理
一.医学影像信息系统(PACS)基本概况 医学影像信息系统(PACS)是一种集影像采集.传输.存储.管理.查询.诊断.报告.归档和科研于一体的综合性应用系统.它基于医学影像存储与通信系统(Pictur ...
- Android源码学习以及在工作中的应用01-TextView
有人说种下一棵树最好的时间是十年前,其次是现在.我已经浪费了整整十年,所以从现在起,脚踏实地,静下心来学习,一切从头开始.期望十年后的自己,无怨无悔. 我们在自动化测试的工作中,有一个这样的场景需求. ...
最新文章
- springboot设置静态资源不拦截的方法
- 微众WeCross 跨链平台(1)平台介绍
- wxWidgets:实时传输时间RTTI
- 判断标签是否出界,重新设置样式
- 4项技巧使你不再为PHP中文编码苦恼
- UVA 1025 A Spy in the Metro DP水题
- [转载] 2020最新Java面试题,常见面试题及答案汇总
- 安卓之实现一个简单的电话拨号功能
- 软件项目失败的心理原因
- 奇安信代码安全实验室帮助谷歌修复 Chrome 沙箱外高危漏洞,获官方致谢
- 电视/电视盒点播APP软件系统定制开发方案
- android gc卡顿,由于频繁GC造成的界面卡顿原因分析
- 【软考软件评测师】第三十三章 数据库系统应用
- 后缀001,002,003等的文件解压
- 基于ROS1.0的stdr simulation搭建多移动机器人(multiple robots)仿真系统
- jersey java_Jersey 入门与Javabean
- 从原子结构,半导体,PN结到MOS管和CMOS
- C语言 输入一个华氏温度F,要求输出摄氏度C。
- Pytorch+LSTM+Attention 实现 Seq2Seq
- isnan函数返回值c语言,C++ std::isnan等函数的使用