AssetBundle加载API
AssetBundle加载API
在Unity 5当中,可以通过4个不同的API来加载AssetBundle,4个API可以用两个条件来区分:
- AssetBundle是 LZMA压缩、 LZ4压缩还是不压缩的
- 加载AssetBundle的平台
这4个API分别是:
- AssetBundle.LoadFromMemoryAsync
- AssetBundle.LoadFromFile
- WWW.LoadFromCacheOrDownload
- UnityWebRequest 的 DownloadHandlerAssetBundle(Unity5.3之后版本)
1 AssetBundle.LoadFromMemoryAsync
Unity不推荐使用这个API
Unity 5.3.3更新: 这个API在Unity 5.3.3被重命名,之前版本叫 AssetBundle.CreateFromMemory,功能是一样的。
AssetBundle.LoadFromMemoryAsync 从托管代码的字节数组(C#的byte[])中加载AssetBundle。它总是会从本地内存中开辟一段连续内存,然后从托管代码的字节数组中拷贝源数据到这段新分配的内存中。如果 AssetBundle 是 LZMA 压缩格式的,拷贝过程中 AssetBundle 会被解压。而 LZ4 压缩格式或者不压缩的 AssetBundle 会原封不动地拷贝过去。
这个 API 内存消耗的峰值最少是 AssetBundle 大小的两倍:一个是 API 创建的本地内存,一个是传递给 API 的托管代码数组。利用这个 API 加载资源之后,这个加载资源将会在内存中出现 3 份拷贝:一个是托管代码字节数组,一个是 AssetBundle 的本地内存,第三个是在 GPU 或者系统内存中的资源本身。
2 AssetBundle.LoadFromFile
Unity 5.3更新: 这个 API 在 Unity 5.3.3 被重命名。在之前的版本中叫做 AssetBundle.CreateFromFile,功能是一样的。
AssetBundle.LoadFromFile 是一个被设计用来从本地存储中(如硬盘和 SD 卡)加载未压缩的 AssetBundle、高效的API。如果 AssetBundle 未压缩或者使用 LZ4 压缩,这个 API 表现如下:
移动设备: API 只会加载 AssetBundle 的 头部数据, 其他的数据保留在磁盘中。当调用加载的方法(也就是 AssetBundle.Load)或者他们的实例 Id 被解引用时才会被按需加载,在这种情况下没有额外的内存开销的。
Unity 编辑器: 这个 API 会将整个 AssetBundle 加载进内存,就像使用 AssetBundle.LoadFromMemoryAsync那样,而不是按需从磁盘上读取资源。当 AssetBundle 加载时,在Unity编辑的Profiler面板会出现一个峰值,但是在实际设备上面并不会出现,所以如果你要优化这个峰值,需要在实际设备上面重新测试。
注意: 在 Unity 5.3 之前版本的安卓设备上,从 StreamingAssets 目录下加载 AssetBundle 会失败。这是因为 StreamingAssets 下的内容会被打包到一个压缩的 .jar 文件中。更详细的内容,请参照 AssetBundle 使用模式 的 “4.2.1项目部署” 小节。这个问题在 Unity 5.4 中已经修复。Unity 5.4 或者以后版本编译的游戏可以使用这个 API 来从 StreamingAssets 里面加载 AssetBundle。
注意: 对于LZMA压缩的AssetBundle来说,AssetBundle.LoadFromFile API在有的Unity版本上会出现总是加载不成功的问题,这个问题在 Unity 5.3.7f1、 Unity 5.4.3f1和之后的版本修复了。(译注:这里是说在 Unity 5.3.7f1之前、 5.4.0f1到Unity 5.4.3f1(不包括)的版本这个API都是有Bug的,之后的版本修复了这个API加载不了LZMA压缩AssetBundle的问题。)
3 WWW.LoadFromCacheOrDownload
WWW.LoadFromCacheOrDownload 对于从远端服务器和本地存储中加载对象来说很有用,可以使用 file:// 链接地址从本地加载文件。如果 AssetBundle 已经在 Unity 的缓存中存在,则它会表现的跟 AssetBundle.LoadFromFile 一样。
如果 AssetBundle 没有被缓存,WWW.LoadFromCacheOrDownload 会从 AssetBundle 的源地址读取它。如果 AssetBundle 是压缩格式,它会使用一个 worker 线程来解压 AssetBundle 并且写入到缓存当中。如果AssetBundle没有压缩,worker 线程会直接将它写入缓存中。
一旦 AssetBundle 被缓存了,WWW.LoadFromCacheOrDownload 会从缓存中加载 Header 信息和未压缩的 AssetBundle。之后这个 API 表现就跟 AssetBundle.LoadFromFile 一样了。
注意: 当数据被解压并写到缓存的同时,WWW 对象会在本地内存中保留一份 AssetBundle 字节的完整拷贝。这个 AssetBundle 的额外的拷贝是用来支持 WWW.bytes 属性的。
由于 WWW 对象缓存 AssetBundle 的字节数组的开销,这里推荐开发者使用 WWW.LoadFromCacheOrDownload API的 AssetBundle 保持尽可能小(最多几 M )。也推荐开发者在内存有限平台上,如移动设备,确保他们的代码在同时只有一个 AssetBundle 在下载来避免内存峰值。关于 AssetBundle 的大小,请参照 AssetBundle 使用模式 章节中的 “4.3资源分配策略” 小结。
注意: 每调用一次这个 API 都会生成一个新的 worker 线程,要当心多次调用这个 API 的时候多产生多个线程的问题。如果有 5 到 10 个 AssetBundle 需要下载,建议代码只让少数几个 AssetBundle 同时下载。
4 AssetBundleDownloadHandler
在 Unity 5.3 的移动平台上,Unity 引入了 UnityWebRequest API,它比 Unity 的 WWW API 更灵活。UnityWebRequest 可以让开发者指定 Unity 怎么样处理数据和避免不必要的内存开销。使用 UnityWebRequest 去下载一个 AssetBundle 的最简单的方式就是调用 UnityWebRequest.GetAssetBundle API。
在这篇文章中,我们感兴趣的类是 DownloadHandlerAssetBundle。使用时,它的行为跟 WWW.LoadFromCacheOrDownload 类似。它使用 worker 线程去下载数据到固定大小 Buffer 中,然后根据Doanload Hanlder 的设置,把 Buffer 中的数据写到临时存储或者 AssetBundle 缓存中。LZMA 格式压缩的 AssetBudnle 会在下载和缓存过程中被解压。
所有的这些操作都是发生在 Unity底层代码(native code)里,就避免了撑大C#托管堆(managed heap),另外, Download Handler在Unity底层代码也 不 保留所有下载字节数组的拷贝,更加减少了下载AssetBundle的内存开销。
当下载完成之后,Doanload Handler 的 assetBundle 属性用来访问已下载的 AssetBundle,就像对下载后的 AssetBundle 执行了 AssetBundle.LoadFromFile 一样。
UnityWebRequeset 也支持像 WWW.LoadFromCacheOrDownload 一样缓存机制。如果给 UnityWebRequest 对象提供给了缓存信息,并且请求的 AssetBundle 已经在 Unity 的缓存中,AssetBundle 会马上生效并且这个 API 就像 AssetBundle.LoadFromFile 一样操作它。
注意: Unity AssetBundle 缓存机制在 WWW.LoadFromCacheOrDownload 和 UnityWebReuqest 之间是共享的,一个API下载过AssetBundle就其它的API来说缓存也生效。
注意: 不像 WWW, UnityWebRequest 系统拥有一个内部的 worker 线程池,和内部的任务系统去确保开发者不会同时开启大量线程去下载,目前这个线程池的大小是不能配置的。
5 建议
一般的,应该尽可能的使用 AssetBundle.LoadFromFile,这个 API 在速度,磁盘使用率和运行时内存方面都是最高效的。
对于需要下载 AssetBundle 或者给 AssetBundle 打补丁的项目,强烈推荐在 Unity 5.3 或更新版本中使用 UnityWebRequest ,在 Unity 5.2 或者更老版本中使用 WWW.LoadFromCacheOrDownload。就像在下一章的 “4.2 部署” 章节中提到,可以在项目安装的时候(下载器)将 AssetBundle包 解压从而事先准备好 AssetBundle缓存。
当使用 WWW.LoadFromCacheOrDownload 时,为了避免内存峰值引起的程序闪退,强烈推荐确保 AssetBundle 保持在项目最大内存预算的 2-3%。对于大多数项目而言,AssetBundle 的文件大小最好不要大于 5M ,并且不要超过 2 个 AssetBundle 在同时下载。
当使用 WWW.LoadFromCacheOrDownload 或者 UnityWebRequest 是,确保下载的代码在加载完 AssetBundle 后正确的调用 Dispose。C# 的 using 是确保 WWW 或者 UnityWebRequest 的 Dispose 方法会被调用 的最简便的做法。
对于一个有着大型开发团队的项目来说,自定义下载器对于缓存和下载新内容是很有必要的。写一个自定义的下载器是一个艰巨的工程,特别是下载器要和AssetBundle.LoadFromFile兼容的话。更多详情,查看下章节中的 “4.2部署” 章节。
AssetBundle加载API的更多相关文章
- Unity5.x版本AssetBundle加载研究
之前说了 “Unity5.x版本AssetBundle打包研究”,没看过的请先看一下:http://www.shihuanjue.com/?p=57 再来看本文,有一定的连接性. 先梳理一下思路: 要 ...
- U3D assetbundle加载与卸载的深入理解
using UnityEngine; using System.Collections; using System; public class testLoadFromAB : MonoBehavio ...
- U3D assetbundle加载
using UnityEngine; using System.Collections; public class testLoadFromAB : MonoBehaviour { IEnumerat ...
- Unity5系列资源管理AssetBundle——加载
上次我们进行了AssetBundle打包,现在我们还把打包的资源加载到我们的游戏中.在加载之前,我们需要把打包好的Bundle包裹放到服务器上,如果没有,也可以使用XAMPP搭建本地服务器. 加载的A ...
- Unity5-ABSystem(三):AssetBundle加载
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/lodypig/article/detai ...
- [原]unity5 AssetBundle 加载
本文unity版本5.1.3 一.现有的打包教程: 1.http://liweizhaolili.blog.163.com/blog/static/16230744201541410275298/ 阿 ...
- Android开发中如何加载API源码帮助开发
在eclipse中添加android源码既可以帮助我们的开发,又能使我们边开发边学习. android环境的搭建:http://blog.csdn.net/dawanganban/article/de ...
- 详谈 Unity3D AssetBundle 资源加载,结合实际项目开发实例
第一次搞资源更新方面,这里只说更新,加载,AssetBundle资源加载,谈谈自己的理解,以及自己在项目中遇到的那些神坑,现在回想一下,真的是自己跪着过来的,说多了,都是泪. 我这边是安卓AssetB ...
- AssetBundle异步加载被中断的问题
刘 刘泰言创建于 1 年前 在使用异步接口 yield return AssetBundle.ASyncLoad的时候,难免会想到:这个异步处理完之前如何Cancel掉这个任务?也就是一个AssetB ...
随机推荐
- 微软YY公开课[《微软中国云计算Azure平台体验与新企业架构设计》 周六晚9点
YY频道是 52545291//@_勤_: YY账号真的是一次一账号啊! 全然记不得之前注冊的//@老徐FrankXuLei: 最火爆的微软免费公开课.第一次顶峰126人.第二次96人.第三次我们又来 ...
- 1692. [USACO07DEC] 队列变换【后缀数组+贪心】
Description FJ打算带他的N(1 <= N <= 30,000)头奶牛去参加一年一度的“全美农场主大奖赛”.在这场比赛中,每个参赛者都必须让他的奶牛排成一列,然后领她们从裁判席 ...
- 「GXOI / GZOI2019」旧词
题目 确定这不是思博题 看起来很神仙,本来以为是\([LNOI2014]LCA\)的加强版,结果发现一个点的贡献是\(s_i\times (deep_i^k-(deep_i-1)^k)\),\(s_i ...
- swoole_table测试
public function test() { $count = []; $count[] = ['key' => 'name', 'type' => ...
- empty与isset,null与undefined
一. null VS undefined VS NaN 1. null 定义:null是特殊的object,是空对象,没有任何属性和方法. document.writeln(typeof null); ...
- 404 Note Found 队-Beta1
目录 组员情况 组员1(组长):胡绪佩 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示组内最新成果 团 ...
- 罗技 HTPC K700
1.下方的 播放,暂停 快进 可以控制midea 2.CTRL+ALT+FN+(PG UP)可开启触控板左键点击功能3.FN(功能键)+左键=右键功能
- 学习scalaenv
背景 最近由于工作需要, 我总是在不同的scala项目间流动开发. 这就遇到一个很棘手的问题, 这几个项目用的scala版本不一致, 老项目用的是 scala 2.11.8, 新项目用的是 scala ...
- R语言学习笔记(十九):字符串处理中预定义字符组(表格介绍)
R中预定义的字符组 代码 含义说明 [:digit:]或\\d 数字; [0-9] [^[:digit:]]或\\D 非数字; 等价于[^0-9] [:lower:] 小写字母; [a-z] [:up ...
- ALV-TREE -转
****要注意创建相应程序的屏幕0100**** 在一些情况下,输出的ALV可能用树形结构更容易展现数据之间的相互关联,为了输出ALV-TREE主要用到的是容器类(如CL_GUI_CONTAINER或 ...