1

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

 3 years ago
source link: https://blog.uwa4d.com/archives/TechSharing_244.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

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


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

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

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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/605c4aa0cfa35d5b53669c57


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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6059b14acfa35d5b53669bdd


Texture

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

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

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

1.png

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

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

感谢郑骁@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/60589217cfa35d5b53669bce


Android

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

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

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

2.png

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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/6057fab6cfa35d5b53669b74


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问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/60558f8bcfa35d5b53669b6b

封面图来源: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(原群已满员)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK