android性能优化(一)之UI渲染优化

发布时间:2024-09-05 18:58:26 浏览量:113次

阅读本文大概需要 2.6 分钟。

在众多高频面试题中,Android性能优化几乎可以说是必问的考题。

而此题一出,一场恶战已然拉开序幕,因为此话题牵扯面非常广,绝非三言两语就能够聊完。因此,非常有必要对性能优化做一下系统性的总结。

此篇作为性能优化系列开篇,是因为UI渲染优化最为初级,且杂项很多,面试时可以作为回答的起点。

对于UI渲染优化,记住一个宗旨:尽量减少 layout 布局嵌套层级和 View 个数。后面几项其实都是围绕着这个宗旨来做具体的优化的。

减少嵌套层级是减少 View 树的深度,原因一是如果 View 树过深,会导致 findViewById() 方法查找耗时,因为 findViewById 始终是从 rootView 开始深度优先遍历,二是会导致绘制重叠,从而造成过度绘制。

减少 View 个数,不言而喻能用最少的 View 个数实现 UI 效果,能够避免不必要的测量,放置,绘制的计算时间,和 View 的查找时间。

从代码的可读性和可维护性上来讲,最简洁的东西也是最好的。

一. 布局优化

1)尽量选用 RelativeLayout,ConstraintLayout,LinearLayout,并发挥它们的特性使布局扁平化。同等扁平的情况下,选用 LinearLayout 性能更佳。

2)利用系统提供 View 的特殊属性,比如 TextView 的 drawableStart 属性等设置 icon,就没有必要再增加一个 ImageView。TextView 滑动属性来避免嵌套一层 ScrollView。

3)include 一个 layout 时,可以考虑使用 merge 标签,如果布局的最外层和它所在的父容器控件相同,那么使用 merge 可以减少一个嵌套层级。

4)当某个布局的显现需要条件时,比如断网,获取数据失败等显示的 UI,可以考虑使用 ViewStub。其本质是一个宽高为 0 的 View,非常轻量级,当需要显示时再 inflate 或者 visible=true 才会加载其布局。

5)使用 LinearLayout 自带的 divider 属性实现分割线,而不是在布局中手动添加一个额外的 View 作为分割线。

6)使用 Space 控件(而非 View,LinearLayout 等)进行合理的占位。其本质是一个 onDraw 实现为空的 View,因此它只占位置,而不去渲染,使用它来进行占位填充比其他控件更加高效。

二. 自定义 view 优化

1)onDraw 中避免对象的分配。原因是 onDraw 会执行多次,将导致频繁的 GC,内存抖动,损耗性能。

2)使用 Canvas 的 ClipRect 方法避免过度绘制。

三. 过度绘制

所谓过度绘制,就是 GPU 在同一区域进行了不必要的多次绘制。如果进行真机调试,打开“调试 GPU 过度绘制”,就能看到不同的区域有不同的颜色,表示过度绘制严重的程度。

过度绘制的原因就是嵌套层级过深,而且设置了多余的背景色和不可见区域的绘制所导致。

1)在合适的地方设置背景。

比如要对 Activity 设置背景颜色,无需在其根 Layout 上设置其 background,因为系统本身就是把 Activity 的 xml 布局添加到一个叫“content”的 FrameLayout 中,Android 系统本身已经对这个 FrameLayout 设置了背景颜色。

如果我们在 layout.xml 的根 View 中再设置背景颜色,就相当于 GPU 在同一区域绘制了 2 次背景色,导致过度绘制。

解决的办法有 2 种:

public class MyActivity extends AppCompatActivity { @Override  protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //在 setContentView 之前 findViewById(android.R.id.content).setBackgroundResource(xxx); setContentView(R.layout.xxx); //在自己的根 layout 中设置背景}
public class MyActivity extends AppCompatActivity { @Override  protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState);  setContentView(R.layout.xxx); //在自己的根 layout 中设置背景 getWindow().setBackgroundDrawable(null) //在 setContentView 之后}

2)不可见区域不要绘制,ClipRect & QuickReject。

当我们在自定义 View 中用到 ClipRect 时,请只在 ClipRect 这个可见的矩形区域内进行绘制,而且通过 QuickReject 来判断另一个绘制的矩形区域是否和 ClipRect 所在矩形区域有相交,若无,则可避免区域外的绘制。

一切从 android 的 handler 说起(一)之 message

一切从 android 的 handler 说起(二)之 threadLocal

一切从 android 的 handler 说起(三)之 UI 线程不卡顿

一切从 android 的 handler 说起(四)之 postDelay 原理

一切从 android 的 handler 说起(五)之触摸事件模型

一切从 android 的 handler 说起(六)之生命周期来源

一切从 android 的 handler 说起(七)之 Handler 内存泄露


进入公众号,回复“程序员“可以领取一份计算机技术电子书福利合集

欢迎转发,关注公众号 火星时代

每天几分钟,掌握一个硬核面试知识点

热门课程推荐

热门资讯

请绑定手机号

x

微信扫码在线答疑

扫码领福利1V1在线答疑

点击咨询
添加老师微信,马上领取免费课程资源

1. 打开微信扫一扫,扫描左侧二维码

2. 添加老师微信,马上领取免费课程资源

同学您好!

您已成功报名0元试学活动,老师会在第一时间与您取得联系,请保持电话畅通!
确定