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. 【Alpha】Daily Scrum Meeting——blog3

    团队成员 吴吉键 201421122007(组长) 魏修祺 201421122008 孙劲林 201421122022 1. 会议当天照片 2. 每个人的工作 姓名 已完成工作 计划完成工作 遇到的困 ...

  2. Hadoop HA 高可用集群的搭建

    hadoop部署服务器 系统 主机名 IP centos6.9 hadoop01 192.168.72.21 centos6.9 hadoop02 192.168.72.22 centos6.9 ha ...

  3. ajax 跨域解决方法

    最近在开发过程中,使用ajax去异步调取图片.在开发中这个功能没什么问题,可以后来提测,重新部署之后就有问题了,这就是ajax的跨域问题. ajax核心对象XMLHttpRequest本身是不支持跨域 ...

  4. 使用Oracle的instr函数与索引配合提高模糊查询的效率

    使用Oracle的instr函数与索引配合提高模糊查询的效率 一般来说,在Oracle数据库中,我们对tb表的name字段进行模糊查询会采用下面两种方式:1.select * from tb wher ...

  5. Yii安装使用教程(转)

    Yii 是一个基于组件的高性能 PHP 框架,用于快速开发大型 Web 应用.它使Web开发中的 可复用度最大化,可以显著提高你的Web应用开发速度.Yii 这个名字(读作易(Yee) 或 [ji:] ...

  6. 解决Mac外接显示器经常没反应

    问题描述 最近在使用绿联扩展坞的时候,发现连接显示器时,有时插上后可以正常使用,有时插上后显示器没反应. 解决办法 经过一段时间的尝试,发现这样操作可以避免出现这种问题: 关机的时候: 从转换器拔掉H ...

  7. C++ pair(对组)的简单了解

    类模板:template<class T1,class T2> struct pair 参数:T1是第一个值得数据类型,T2是第二个值的数据类型. 功能:pair将一对值组合成一个值, 这 ...

  8. MySQL(三)架构

    和其他数据库相比,MySQL有点与众不同,他的架构可以在多种不同场景中应用并发挥好的作用,但同时也会带来一点选择上的困难.MySQL并不完美,却足够灵活,能够适应高要求的环境.为了充分发挥MySQL的 ...

  9. $2018/8/15 = Day \ \ 1$杂题整理

    \(\mathcal{Morning}\) \(Task1\)高精度\(\times\)高精度 哦呵呵--真是喜闻乐见啊,我发现这一部分比较有意思于是就打算整理下来233.窝萌现在有一个整数\(A = ...

  10. C语言程序设计I—第六周教学

    第六周教学总结(8/10-14/10) 教学内容 第二章 用C语言编写程序 2.4 输出华氏-摄氏温度转换表 课前准备 在蓝墨云班课发布资源: PTA:2018秋第六周作业 分享码:88C28D89E ...