AssetBundle加载API

在Unity 5当中,可以通过4个不同的API来加载AssetBundle,4个API可以用两个条件来区分:

  1. AssetBundle是 LZMA压缩、 LZ4压缩还是不压缩的
  2. 加载AssetBundle的平台

这4个API分别是:

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的更多相关文章

  1. Unity5.x版本AssetBundle加载研究

    之前说了 “Unity5.x版本AssetBundle打包研究”,没看过的请先看一下:http://www.shihuanjue.com/?p=57 再来看本文,有一定的连接性. 先梳理一下思路: 要 ...

  2. U3D assetbundle加载与卸载的深入理解

    using UnityEngine; using System.Collections; using System; public class testLoadFromAB : MonoBehavio ...

  3. U3D assetbundle加载

    using UnityEngine; using System.Collections; public class testLoadFromAB : MonoBehaviour { IEnumerat ...

  4. Unity5系列资源管理AssetBundle——加载

    上次我们进行了AssetBundle打包,现在我们还把打包的资源加载到我们的游戏中.在加载之前,我们需要把打包好的Bundle包裹放到服务器上,如果没有,也可以使用XAMPP搭建本地服务器. 加载的A ...

  5. Unity5-ABSystem(三):AssetBundle加载

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/lodypig/article/detai ...

  6. [原]unity5 AssetBundle 加载

    本文unity版本5.1.3 一.现有的打包教程: 1.http://liweizhaolili.blog.163.com/blog/static/16230744201541410275298/ 阿 ...

  7. Android开发中如何加载API源码帮助开发

    在eclipse中添加android源码既可以帮助我们的开发,又能使我们边开发边学习. android环境的搭建:http://blog.csdn.net/dawanganban/article/de ...

  8. 详谈 Unity3D AssetBundle 资源加载,结合实际项目开发实例

    第一次搞资源更新方面,这里只说更新,加载,AssetBundle资源加载,谈谈自己的理解,以及自己在项目中遇到的那些神坑,现在回想一下,真的是自己跪着过来的,说多了,都是泪. 我这边是安卓AssetB ...

  9. AssetBundle异步加载被中断的问题

    刘 刘泰言创建于 1 年前 在使用异步接口 yield return AssetBundle.ASyncLoad的时候,难免会想到:这个异步处理完之前如何Cancel掉这个任务?也就是一个AssetB ...

随机推荐

  1. 解决数据库自增ID的问题

    (1)设置主键自增为何不可取这样的话,数据库本身是单点,不可拆库,因为id会重复. (2)依赖数据库自增机制达到全局ID唯一使用如下语句:REPLACE INTO Tickets64 (stub) V ...

  2. JDK1.6在LINUX下的安装配置[转]

    JDK1.6在LINUX下的安装是如何进行的呢,让我们开始我们的演示: Ubuntu Linux下jdk的安装与配置 1.JDK1.6安装准备 从sun公司网站www.sun.com下载linux版本 ...

  3. BZOJ2281:[SDOI2011]黑白棋(博弈论,组合数学,DP)

    Description 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色不同. 小 ...

  4. 理解Flux架构

    本文摘自<Flux架构入门教程>和<谈一谈我对 React Flux 架构的理解>.也有自己的观点和总结.转载请注明出处. 一.Flux架构描述 1. Flux是什么 Flux ...

  5. JIRA使用方法,简易图解

          我们公司要用版本控制(SVN)和过程管理(JIRA)相配合开发软件,所以两个都得用喽!     JIRA是集项目计划.任务分配.需求管理.错误跟踪于一体的商业软件.JIRA创建的问题类型包 ...

  6. 【题解】洛谷P4158 [SCOI2009] 粉刷匠(DP)

    次元传送门:洛谷P4158 思路 f[i][j][k][0/1]表示在坐标为(i,j)的格子 已经涂了k次 (0是此格子涂错 1是此格子涂对)涂对的格子数 显然的是 每次换行都要增加一次次数 那么当j ...

  7. SpringBoot与mongodb的结合

    本文系列文章: ​ 使用Shell 操作 MongoDB的技巧 ​ MongoTemplate的使用技巧及其注意事项 敬请期待. 前言 最近公司想要做一个用户行为数据的收集,最开始想用mysql来存储 ...

  8. 不安分的android开发者(小程序初尝试,前后台都自己做)

    前言 作为一个稍微有点想法的程序员来说,拥有一个自己开发,自己运营,完全属于自己的应用,应该是很多人的梦想.刚毕业那会,自己的工作是做游戏,于是也和朋友业余时间开发一些小游戏玩玩,可是终究不成气候,而 ...

  9. 20155238 2016-2017-2 《JAVA程序设计》第七周学习总结

    教材学习内容总结 第十二章 认识Lambda语法 在只有Lambda表达式的情况下,参数的类型必须写出来. 匿名类有相应的应用场合.Lambda表达式只关心方法命名上的参数与返回定义,忽略方法名称. ...

  10. 2015306 白皎 《网络攻防》Exp5 MSF基础应用

    2015306 白皎 <网络攻防>Exp5 MSF基础应用 一.基础问题 用自己的话解释什么是exploit,payload,encode. exploit指由攻击者或渗透测试者利用一个系 ...