问答 如何优化 UI 中大量使用 SetActive 的问题

侑虎科技 · March 31, 2021 · 934 hits

1)如何优化 UI 中大量使用 SetActive 的问题
​2)ASTC 压缩和 ETC2 压缩打出的 APK 包的问题
3)PNG 图片格式与 TGA 图片格式问题
4)游戏运行的崩溃问题
5)关于 AssetBundle 加载方式的适用环境


这是第 244 篇 UWA 技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间 10 分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)

UI

Q:在 UI 的日常开发中为了显示或者隐藏某些 GO 使用了大量的 SetActive(true)/(false) 代码。但是 SetActive 的开销过大,所以不想使用 SetActive,是否有其他解决方法?

A1:这种情况下 Active/Deactive 的开销主要有几个方面:

1.C# 层到 Native 层的穿梭调用速度比 C# 层内的速度慢。
2.UI 元素的变化导致所在的 Canvas 变化,触发函数 Canvas.SendWillRenderCanvases() 与 Canvas.BuildBatch() 造成高耗时。
3.UI 元素的网格顶点数组改变会造成堆内存分配,触发 GC,导致耗时(不过对 UI 元素进行位置移动不会造成堆内存分配)。

因此,优化也可以从以下几点考虑:

1.在 C# 层设置变量来标识相应的 GO 处于 Active 还是非 Active 状态,避免对 Active 的对象进行 SetActive(true),避免对非 Active 的对象进行 SetActive(false)。

对 Active 进行 SetActive(true) 时,“底层” 会进行判断,但调用的时候,就已经是从 C# 层调用底层,导致开销较高。在 C# 层判断好,就避免了让底层判断。

2.将要频繁变化的 UI 元素与不频繁变化的 UI 元素放在不同的 Canvas 中,减少 UI 元素变化时的耗时。

3.通过将 UI 元素的坐标移动到 Canvas 的范围之外的方法来显示与隐藏,避免 SetActive 的耗时以及 SendWillRenderCanvases 的耗时。

4.经测试,对 Component 进行 enabled = false 的操作比对 GO 进行 SetActive(false) 的操作耗时低。

5.通过添加 CanvasGroup 组件设置透明度的方式来进行显示与隐藏。

感谢 Prin@UWA 问答社区提供了回答

A2:最近做优化,也发现了这个问题,尤其是挂 Image 和 TMPText 的在 SetActive 的时候耗时更差。我准备从以下方面做优化:

1.对于挂 UICanvas 的直接修改 Layer 层。

2.对于不挂 UICanvas 的,改成挂 CanvasGroup 来控制 Alpha.

这个地方有个麻烦的点。因为我们项目开了很久,让拼界面的同学去到需要控制的节点上挂 CanvasGroup 不太现实。在运行时动态挂组件,对性能有些担忧。所以打算改成运行时遇到修改 Active 的节点,到对应的 Prefab 下增加一个 CanvasGroup 控件,这样 Prefab 就补全 CanvasGroup 控件了。在正式上线之后,如果有遗漏不存在的,直接使用 SetActive。

3.使用 CanvasGroup 方式有个缺点,只是改变了 Alpha,依然会占有布局,所以父界面是 Layout 的,不能采用 CanvasGroup。初步计划是对比 SetScale0 和 SetActive 的耗时,两者应该都会引起重绘。

感谢承影@UWA问答社区提供了回答

Texture

Q:在一个空工程里面,我放了几张大图 2048*2048 的,采用 ETC2 4bits 的格式压缩的时候单张大小为 2MB,采用 ASTC 6X6 压缩的时候单张大小是 1.8MB。

按照我的理解:采用 ASTC 压缩格式打出的 APK 应该更小才对,可是事实和我预想的相反:采用 ETC2 压缩打出的 APK 为 21.1MB;采用 ASTC 压缩打出的 APK 为 25.7MB。

为什么采用 ETC2 压缩的包体反而更小呢?ASTC 打出的 APK 更大呢?

A:占用包体的大小和在 Editor 下的 Preview 界面看到的大小是两回事。

Preview 界面看到的大小是 ASTC 或者 ETC2 格式的资源的大小,而打包后,会对资源进行进一步的压缩(LZ4 或 LZMA)。只能说明 ETC2 压缩成 LZ4 后占用的包体大小确实比 ASTC 压缩成 LZ4 后占用的大小更小,至于原因就要看具体压缩算法的实现了。

可以用 AssetBundle 来验证,如果打 AssetBundle 包时选择 NoCompression,那么确实 ASTC 格式的比 ETC2 格式的 AssetBundle 包更小。如果选择 LZ4 或 LZMA 压缩,那么 ETC2 格式的 AssetBundle 包比 ASTC 格式的 AssetBundle 包要小。

感谢 Prin@UWA 问答社区提供了回答:

Texture

Q:美术说有一张带透明通道的图,必须出 TGA 格式,不能出 PNG 格式的图,缺少透明通道。请问为什么 PNG 格式在 Unity 中有些是有透明通道的?该怎么让美术在 PhotoShop 中出一张 PNG 格式图,又能满足效果的?可否详细说下这两者图在 Unity 中的区别原理?

A1:在 PhotoShop 中针对 PNG 并没有透明通道这一说。导出也只能导出 RGB3 个通道。想要修改 PNG 像素的透明信息需要用到蒙板。

你和美术同学说 “这块的信息画在蒙版上,黑透白不透”,他就明白了。

感谢张首峰@UWA问答社区提供了回答

A2:选 TGA 美术比较好处理,也不用关心 PNG 那几种格式的区别,PhotoShop 里也不用处理 Alpha 的事,毕竟在引擎里都要根据不同平台进行压缩处理。不在乎工程大小的情况下,流程更方便才是关键。

感谢郑骁@UWA问答社区提供了回答

Android

Q:游戏运行过一段时间后某些机器会出现以下所示的崩溃,具体 Log 可戳原问答查看,请问有遇到过类似的问题吗?

JNI ERROR (app bug): global reference table overflow (max=51200)

我看 Unity 2018.3 里面有一个是相关内容,我们现在用的版本是 2019.4.10,按说应该已经修好了,望各位大佬指导迷津,谢谢!

A1:是不是 JNI 调用次数太多了?我之前试过,有个腾讯语音的 API 一直在调用 JNI,运行到一定时间后就崩溃了,日志好像跟你一样。

感谢 Jam@UWA 问答社区提供了回答

A2:应该是 AndroidJavaClass 和 AndroidJavaObject 只频繁 New 没调用 Dispose 导致的。

感谢上山打野@UWA问答社区提供了回答

A3:参考以下信息:

2019.4.21f1 Release Notes
Fixes

  • Android: Fixed Java local reference leaking when using AndroidJavaClass/Object. (1283209)

https://unity3d.com/unity/whats-new/2019.4.21 的 Fixes 里。

感谢 littlesome@UWA 问答社区提供了回答

AssetBundle

Q:关于 AssetBundle 加载方式的适用环境中,AssetBundle.LoadFromMemory 以及 AssetBundle.LoadFromStream 适用环境分别是什么?

A1:AssetBundle.LoadFromMemory
1.使用 UnityWebRequest 下载的 AssetBundle 资源并且使用后不存到本地;
2.有加密需求的 AssetBundle 资源。

AssetBundle.LoadFromStream
1.有加密需求的 AssetBundle 资源(内存值理论上比 AssetBundle.LoadFromMemory 小);
2.Android 下需要 Copy 出 StreamingAssets 目录外,创建流。

感谢郑骁@UWA问答社区提供了回答

A2:当资源有加密需求时,可先把 AssetBundle 读取到内存当中,进行解密后再调用该 AssetBundle.LoadFromMemory 进行加载。该方法消耗的最大内存量将至少是 AssetBundle 的两倍。可参考《AssetBundle 的原理及最佳实践》

AssetBundle.LoadFromStream 可进行流式加载,不需要将 AssetBundle 全部读到内存中再解密、加载,而是可以通过每次像 Buffer 中读一部分,解密一部分的方式进行加载,不会多占用一份很大的内存。如果使用该接口,需要自定义一个继承 FileStream 类,然后在 Read 和 Write 方法内对 Byte 数组进行异或加密解密处理。

具体用法可参考:https://www.xuanyusong.com/archives/4607

感谢 Prin@UWA 问答社区提供了回答

封面图来源:UiFaderPro
一组使 Unity 引擎中的 UI(4.6b + uGUI)的淡入淡出变得容易的脚本。
https://lab.uwa4d.com/lab/5b5d2aaad7f10a201feadf62


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在 UWA 问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之 “石”,也能攻你之 “玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA 学堂:edu.uwa4d.com
官方技术 QQ 群:793972859(原群已满员)

No Reply at the moment.
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up