
前言很多开发者在工作中一直和UI打交道所以认为UI非常的简单事实上对于90%的开发者来说不知道UI的本质原理。虽然在开发中我们在接到产品的UI需求之后可以走捷径照抄大型APP代码但是copy来的代码一旦出了问题也只是百度或者靠猜的方案去解决。真正高级的工程师也会使用别人的代码但是他们深入理解了高级UI的原理及性能优化方法就能避免卡顿的情况。相信大家多多少少看过一些高级UI原理的文章但是一到用的时候就不知道了本文就给大家讲清楚从生命周期分析UI原理Activity的attach 方法里创建PhoneWindow。onCreate方法里的 setContentView 会调用PhoneWindow的setContentView方法创建DecorView并且把xml布局解析然后添加到DecorView中。在onResume方法执行后会创建ViewRootImpl它是最顶级的View是DecorView的parent创建之后会调用setView方法。ViewRootImpl 的 setView方法会将PhoneWindow添加到WMS中通过 Session作为媒介。setView方法里面会调用requestLayout发起绘制请求。requestLayout 一旦发起最终会调用 performTraversals 方法里面将会调用View的三个measure、layout、draw方法其中View的draw 方法需要一个传一个Canvas参数。最后通过relayoutWindow 方法将Surface跟当前Window绑定通过Surface的lockCanvas方法获取Surface的的Canvas然后View的绘制就通过这个Canvas最后通过Surface的unlockCanvasAndPost 方法提交绘制的数据最终将绘制的数据交给SurfaceFlinger去提交给屏幕显示。UI优化UI优化主要包括布局优化以及view的绘制优化。先说下UI的优化到底是什么有些时候我们打开某个软件会出现卡顿的情况。这就是UI的问题。那么我们想一下什么情况会导致卡顿呢一般是如下几种情况人为在UI线程中做轻微耗时操作导致UI线程卡顿布局Layout过于复杂无法在16ms内完成渲染同一时间动画执行的次数过多导致CPU或GPU负载过重View过度绘制导致某些像素在同一帧时间内被绘制多次从而使CPU或GPU负载过重View频繁的触发measure、layout导致measure、layout累计耗时过多及整个View频繁的重新渲染内存频繁触发GC过多同一帧中频繁创建内存导致暂时阻塞渲染操作冗余资源及逻辑等导致加载和执行缓慢臭名昭著的ANR可以看见上面这些导致卡顿的原因都是我们平时开发中非常常见的。有些人可能会觉得自己的应用用着还蛮OK的其实那是因为你没进行一些瞬时测试和压力测试一旦在这种环境下运行你的App你就会发现很多性能问题。下面就分享给大家几种常见的UI 优化方式。所谓UI优化就是拆解渲染过程的耗时找到瓶颈的地方加以优化。前面分析了UI原理Activity、Window、DecorView、ViewRootImpl之间的关系以及XML布局文件是如何解析成View对象的。耗时的地方View的创建在主线程包括measure、layout、draw界面复杂的时候这一部分可能会很耗时。解析XML反射创建VIew对象这一过程的耗时。下面介绍一些常用的UI优化方式~3.1 常规方式减少UI层级、使用merge、Viewstub标签优化优化layout开销、RelativeLayout和带有weight的Linearlayout会测量多次,可以尝试使用ConstraintLayout 来代替。背景优化分析DecorView创建的时候发现DecorView会设置一个默认背景可以统一将DecorView背景设置为通用背景其它父控件就无需设置背景避免重复绘制。3.2 xml转换成代码使用xml编写布局很方便但是最终要通过LayoutInflater的inflate方法将xml解析出来并递归反射去创建View对象布局比较复杂的时候这一部分会非常耗时。使用代码创建可以减少xml递归解析和反射创建View的这部分耗时。当然如果将xml都换成代码来写开发效率将不忍直视并且代码可读性也是个问题。掌阅开源的一个库编译期自动将xml转换成java代码X2C它的原理是采用APTAnnotation Processor Tool JavaPoet技术来完成编译期间【注解】-【解注解】-【翻译xml】-【生成java】整个流程的操作即在编译生成APK期间将需要翻译的layout翻译生成对应的java文件这样对于开发人员来说写布局还是写原来的xml但对于程序来说运行时加载的是对应的java文件。侵入性极低去除注解则回退到原生的运行时解析方式。当然有些情况是不支持转换的比如merge标签编译期没法确定它的parent。3.3 异步创建View通过子线程创建View减少主线程耗时。private void threadNewView() { new Thread(){ Override public void run() { mSplashView LayoutInflater.from(MainActivity.this).inflate(R.layout.activity_splash,null); } }.start(); }当然这种方式需要处理同步问题并且没有从源头上解决创建View耗时只是将这部分耗时放到线程去做。UI更新的操作还是要切换到主线程不然会触发ViewRootImpl的checkThread检测。void checkThread() { if (mThread ! Thread.currentThread()) { throw new CalledFromWrongThreadException( Only the original thread that created a view hierarchy can touch its views.); } }3.4 复用View复用View这个应该比较常见了像RecyclerView的四级缓存目的就是通过复用View减少创建View的时间。我们可以在onDestroy方法将View的状态清除然后放入缓存。在onCreate的时候去命中缓存设置状态。3.5 异步布局 Litho正常情况下measure、layout、draw都是在主线程执行的最终绘制操作是在draw方法而measure、layout只是做一些数据准备完全可以放到子线程去做。Litho 的原理就是将measure、layout 放到子线程 github.com/facebook/li…优点将measure、layout、放到子线程去做减少主线程耗时。使用自己的布局引擎减少View层级界面扁平化。优化RecyclerView提高缓存命中率。缺点无法在AS中预览。使用自己的布局引擎有一点的使用成本。3.6 Flutter自绘引擎Flutter 是一个跨平台UI框架内部集成了Skia图像库自己接管了图像绘制流程性能直逼原生是时候制定计划学习一波了~学习的过程中善于总结才能快速提升个人的水平这里我也总结了一份《Android性能优化全方面解析》1586页5个章节95个小点不仅仅有详细的底层原理的解析还有大厂性能优化探索与实践第一章 性能优化心得与经验移动端性能监控方案HertzAndroid性能优化之虚拟机调优Android UI 性能优化美团外卖Android Lint代码检查实践使用Android Studio和MAT进行内存泄漏分析…第二章 响应速度Android App 启动优化全记录Android 中如何计算 App 的启动时间应用启动时间支付宝 App 构建优化解析Redex 初探与 InterdexAndorid 冷启动优化…第三章 流畅度Android 中的卡顿丢帧原因概述Android 无障碍服务导致的整机卡顿案例分析显示性能指标渲染速度缓慢Android 流畅度检测原理简析…第四章 内存Android 中低内存对性能的影响Android OOM案例分析Android 代码内存优化建议Android匿名共享内存Ashmem原理Linux 查看进程消耗内存情况总结…第五章 图形栈Android 中的 Hardware Layer 详解Android硬件加速原理与实现简介Android图形系统概述Choreographer原理SurfaceFlinger启动篇Android应用程序UI硬件加速渲染技术…还有一份《360°全方面性能调优》一共有721页四个章节25个小点。1、设计思想与代码质量优化2、程序性能优化启动速度与执行效率优化布局检测与优化内存优化耗电优化网络传输与数据储存优化APK大小优化3、开发效率优化分布式版本控制系统Git自动化构建系统Gradle4、项目实战启动速度流畅度抖音在APK包大小资源优化的实践优酷响应式布局技术全解析网络优化手机淘宝双十一性能优化项目揭秘高德APP全链路源码依赖分析彻底干掉OOM的实战经验分享微信Android终端内存优化实践由于篇幅限制这里只能展示部分内容朋友们如果需要这份完整版的PDF资料合集微信扫描下方CSDN官方二维码【免费获取】。