Android中卡顿优化布局详细介绍

目录
  • 背景
  • 实践过程
    • 如何渲染界面
    • 什么是过度绘制
    • 如何查看绘制维度
    • 界面优化
    • 硬件加速原理
  • 总结

背景

在当下移动互联网后半场,手机已经是人手必备的设备。App是离用户最近的应用,界面又是最直观影响用户体验的关键部分,其流畅度直接影响用户对产品的评价和留存。

技术是服务于人的,如果技术无法给你带来良好的体验,那技术本身的存在就具有争议。

所以界面性能是至关重要的,不可忽视。

实践过程

布局代码是最基础的,但也是最重要的。

首先我们看个简单小案例

不同深浅的颜色来表示过度绘制:

没颜色:没有过度绘制,即一个像素点绘制了 1 次,显示应用本来的颜色;

蓝色:1倍过度绘制,即一个像素点绘制了 2 次;

绿色:2倍过度绘制,即一个像素点绘制了 3 次;

浅红色:3倍过度绘制,即一个像素点绘制了 4 次;

深红色:4倍过度绘制及以上,即一个像素点绘制了 5 次及以上;

如何渲染界面

CPU(中央处理器) :我们经常听到,是计算机的核心器件,多缓存多分支,适用于复杂的逻辑运算,主要负责Measure,Layout,Record,Execute的计算操作

GPU(图像处理器):我们通常说的显卡核心就是它了。用于结构单一的数据处理(擅长图形计算),主要负责Rasterization(栅格化)操作

谷歌官方对于流畅度的优化也是高度重视的,有界面渲染三核心Vsync、Triple Buffer和Choreographer。

为何是16ms/为何每秒60帧

android系统每隔16ms绘制一帧UI且要在16ms内完成,( 1秒 / 0.016帧每秒 = 62.5帧/秒 )差不多每秒更新60次。这是因为我们大脑和眼睛一般看24Fps的画面就已经是连续的运动了,看60Fps的画面更看不出端倪,但是60帧可以表达出更加绚丽多彩的内容。

一旦没及时绘制,就会出现掉帧问题,也就是常说的卡顿。这是因为绘制的东西太多的话,CPU、GPU处理不及时。

当然了,设备性能越好,处理能力越强,卡顿会越少,玩游戏的电脑配置高也是出于这方面考虑。

那么Android是如何把图像绘制到界面上的呢?

这就用到了上面的CPU/GPU。

GPU负责栅格化操作(Resterization),栅格化是绘制那些Button,Shape,Path,String,Bitmap等组件最基础的操作。它把那些组件拆分到不同的像素上进行显示。这是一个很“费时”的操作(相比人类时间只是眨眼的功夫),GPU的引入就是为了加快栅格化的操作。

CPU负责把UI组件计算成Polygons,Texture纹理,然后交给GPU进行栅格化渲染。流程如下:

为了能够使得App流畅,我们需要在每一帧16ms以内处理完所有的CPU与GPU计算,绘制,渲染等等操作。

有兴趣更深层学习的,可以去看看界面渲染容器DisplayList

什么是过度绘制

Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了N次。但是我们只能看到最上层的UI,这就会导致多层次的UI界面除最上层外对用户都是不可见的,这样就会浪费大量的CPU以及GPU资源,浪费可耻。

这就像我们在纸上固定区域不断图画,但是有最上层最接近你,其他层有个鬼用?

如何查看绘制维度

开发工具有Hierarchy View、Systrace、Track等

真机在开发者选项中有:调试GPU绘制、硬件层更新、GPU视图更新等等

界面优化

在编写Android布局时总会遇到这样或者那样的痛点,比如:

1.有些布局的在很多页面都用到了,而且样式都一样,每次用到都要复制粘贴一大段,有没有办法可以复用呢?2.解决了1中的问题之后,发现复用的布局外面总要额外套上一层布局,要知道布局嵌套是会影响性能的呐;3.有些布局只有用到时才会显示,但是必须提前写好,虽然设置了为invisible或gone,还是多多少少会占用内存的。

首先第一点也是最重要的一点,在刚开始写布局的时候一定要提前想好和规划好,尽可能的减少层级的嵌套。往往越复杂的布局越臃肿,越容易被忽视进而出现性能问题,所以我们写布局就要知道一些技巧来展示布局

1. 如果图片和文字在一起且文字不动态变的话,可以直接使用带文字的图片。

2. 移除没用的布局和控件,假设添加个背景,尽可能在已经布局上放,减少只有背景功能的控件。

3. 减少透明度的使用,假设:#55FFFFFF 和 #888888 颜色类似,建议使用后者,因为前者有Alpha,view需要至少绘制两次。

4. 去掉多余的不可见颜色背景、图片等,只保留最上层用户可见即可

5. 减少布局层次结构,避免多层嵌套推荐使用RelativeLayout、ConstraintLayout等父类布局

6. 基本控件LinearLayout 性能比RelativeLayout高一些,要提前根据UI想好哪个布局更合适,要有的方式,对症下药。

7. 自定义View尽可能只更新渲染局部区域,杜绝不断全部重绘。

8. 推荐使用IDE自带的Lint或者阿里代码检查插件,对于标黄警告等提示重视起来,能改的就改。

除了以上,我们就要解决过度绘制,我们还可以使用抽象布局,它们分别是include、merge和ViewStub三个标签,现在我们就来认识认识它们吧。

Include应该是最常用的了,其翻译是“包含”、“包括”,最佳使用就是把相同代码抽离出来成一个独立的xml文件,当你在某个布局需要使用的时候直接include进来,这样一搞,很好地起到复用布局的效果。不仅可以极大地减少代码量,想要修改的话直接改这一个xml就行了。

它的两个主要属性:layout:必填属性, id属性;

我们还可以重写宽高、边距和可见性(visibility)这些布局属性。但是一定要注意,单单重写android:layout_height或者android:layout_width是不行,必须两个同时重写才起作用。

这些也能玩不不少花样。

Merge介绍

凡事都有利有弊include标签除了上面的优点,也有个问题就是布局嵌套。他必须有一个根布局,这也导致了最终布局嵌套层级可能多一层。

这时候又引出个新的标签标签,这次先说他的局限性:就是你需要提前明确要放到什么父布局中,然后提前设置好merge里面的控件位置。

优点也明显:他是消除多余层级的,标签必须作为根节点出现。不占用空间,他只是将子view“搬运”到你想嵌套的位置。

ViewStub

写布局的时候我们经常会遇到有些效果不必一直显示,需要动态的来设置invisible或gone,这无形中影响了页面加载速度。

Android提供的方案就是ViewStub,他是一个不可见的大小为0的视图,具有懒加载功能,存在于视图中,但只有设置setVisibility()和inflate()方法调用后才会渲染填充视图,能为初始化加载xml布局分散压力,就像负载均衡。

使用案例:进度条,加载网络失败,显示错误消息等等

它有以下三个重要属性:

android:layout:ViewStub需要填充的视图名称,为“R.layout.xx”的形式;

android:inflateId:重写被填充的视图的父布局id。

与include标签不同,ViewStub的android:id属性是设置ViewStub本身id的,而不是重写布局id,这一点可不要搞错了。另外,ViewStub还提供了OnInflateListener接口,用于监听布局是否已经加载了。

但是注意 viewStub.inflate();方法不能多次调用,否则抛出异常:

java.lang.IllegalStateException: ViewStubmusthaveanon-nullViewGroupviewParent

原因是ViewStub源码调用了removeViewInLayout()方法把自己从布局移除了。到这里我们就明白了,ViewStub在填充布局成功之后就会自我销毁,再次调用inflate()方法就会抛出IllegalStateException异常了。此时如果想要再次显示布局,可以调用setVisibility()方法。

还有一个大坑:viewStub.getVisibility()的值一直为0,所以用他来判断是否显示没作用。不要急,其实是setVisibility()方法实际上在设置内部视图的可见性,而不是ViewStub本身。

硬件加速原理

相信经常看到有的文章说开启硬件加速解决卡的问题,但硬件加速是什么呢?

硬件加速的主要原理是通多底层逻辑,将CPU不擅长的图形计算转换成GPU专用指令,让更擅长图形计算的GPU来完成渲染。

硬件加速过程中包含两个步骤 :

构建阶段 : 遍历所有视图,将需要绘制的操作缓存下来,交给单独的Render线程使用GPU进行硬件加速渲染。(这一阶段在主线程中使用CPU构建)

绘制阶段 : 调用OpenGL(即使用GPU)对构建好的视图进行绘制渲染,绘制的内容保存在Graphic Buffer 并交由 SurfaceFlinger 显示。(Android 5.0+ 使用Render Thread线程,专门负责 UI 渲染和动画显示。)

以上证得硬件加速具有不错的优点,但它不是万能的。

我们平时用的时候可能是直接在Application中用,一锅端,这并不严谨,因为硬件加速还没法做到支持所有的绘制操作(比如复杂的自定义View),这样的话就会造成一定的影响:

1. 像素错位等视觉问题

2. 不同设备版本API兼容问题

解决这些问题官方给了解决方案:使用四种级别控制是否硬件加速。

1. Application

2. Activity-为单独页面设置

3. Window级别

4. 单独的view级别关闭加速(View目前不支持动态启动硬件加速)

总结

到此这篇关于Android中卡顿优化布局详细介绍的文章就介绍到这了,更多相关Android卡顿优化布局内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 关于Android冷启动耗时优化详解

    目录 1,背景 2,调研 2.1,Android中启动的方式 2.2,冷启动流程 2.3,启动时间 3,方案 1,冷启动白屏现象 2,启动时间优化 总结 1,背景 最近开发了一个新的App,前期工期紧,做的比较粗放,上线以后发现App启动时间比较长,达到3秒, 启动有白屏,体验也不好,这个只能后期优化了,最好是前期开发就考虑的 2,调研 2.1,Android中启动的方式 1,冷启动:如果App启动时,后台没有该应用进程,那么系统会重新创建一个进程分配给该应用,这种启动方式就是冷启动 2,热启动

  • android RecyclerView的一些优化点介绍

    目录 1.RecycledPool的重用 2.setHasFixedSize(boolean)的使用 3.setHasStableIds(boolean)的使用 4.ViewCacheExtension的使用 5.预加载 6.更新列表的方式 item局部更新 整体列表更新 总结 1.RecycledPool的重用 场景以及使用: 多个RecyclerView出现,并且他们的item布局结构一致,这时候可以进行重用. 在进行RecyclerView的初始化设置时候进行RecycledPool的设置

  • Android性能优化方案详情

    目录 1.指标 2.包大小优化 3.响应时间优化 4.内存优化 5.CPU优化 6.耗电量优化 前言: 上一个季度在百度工作挺忙碌,在最后期限完成了OKR目标,因此有一段时间没有写文章.今天趁有机会想分享下在大型Android项目工程内的一些性能优化方式. 1.指标 量化性能的指标有很多,但最重要的就是以下5种: 包大小 响应时间 内存 CPU 耗电量 优化性能就是可以从以上5点入手. 2.包大小优化 顾名思义就是减少apk包体积大小,apk大小主要取决于res下的资源文件..class文件,

  • Android中卡顿优化布局详细介绍

    目录 背景 实践过程 如何渲染界面 什么是过度绘制 如何查看绘制维度 界面优化 硬件加速原理 总结 背景 在当下移动互联网后半场,手机已经是人手必备的设备.App是离用户最近的应用,界面又是最直观影响用户体验的关键部分,其流畅度直接影响用户对产品的评价和留存. 技术是服务于人的,如果技术无法给你带来良好的体验,那技术本身的存在就具有争议. 所以界面性能是至关重要的,不可忽视. 实践过程 布局代码是最基础的,但也是最重要的. 首先我们看个简单小案例 不同深浅的颜色来表示过度绘制: 没颜色:没有过度

  • Android Service中方法使用详细介绍

     service作为四大组件值得我们的更多的关注 在Android中,Activity主要负责前台页面的展示,Service主要负责需要长期运行的任务.例如,一个从service播放音乐的音乐播放器,应被设置为前台运行,因为用户会明确地注意它的运行.在状态栏中的通知可能会显示当前的歌曲并且允许用户启动一个activity来与音乐播放器交互. Service的两种实现形式 1.非绑定 通过调用应用程序组件(例如Activity)的startService()方法来启动一个服务.一旦启动,服务就会在

  • Android中View绘制流程详细介绍

    创建Window Window即窗口,这个概念在AndroidFramework中的实现为android.view.Window这个抽象类,这个抽象类是对Android系统中的窗口的抽象.在介绍这个类之前,我们先来看看究竟什么是窗口呢? 实际上,窗口是一个宏观的思想,它是屏幕上用于绘制各种UI元素及响应用户输入事件的一个矩形区域.通常具备以下两个特点: 独立绘制,不与其它界面相互影响: 不会触发其它界面的输入事件: 在Android系统中,窗口是独占一个Surface实例的显示区域,每个窗口的S

  • Android Activity的生命周期详细介绍

    Android Activity的生命周期详细介绍 生命周期描述的是一个类从创建(new出来)到死亡(垃圾回收)的过程中会执行的方法.在这个过程中,会针对不同的生命阶段调用不同的的方法. Activity是Android中四大组件之一,是最常见的应用组件,也是用的最多的组件,它能够提供一个界面与用户进行交互.Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:onCreate  onDestory  onStart  onStop  onRes

  • Android 日志系统Logger源代码详细介绍

    我们知道,在Android系统中,提供了一个轻量级的日志系统,这个日志系统是以驱动程序的形式实现在内核空间的,而在用户空间分别提供了Java接口和C/C++接口来使用这个日志系统,取决于你编写的是Android应用程序还是系统组件.在前面的文章浅谈Android系统开发中LOG的使用中,已经简要地介绍了在Android应用程序开发中Log的使用方法,在这一篇文章中,我们将更进一步地分析Logger驱动程序的源代码,使得我们对Android日志系统有一个深刻的认识. 既然Android 日志系统是

  • Android四大组件之Activity详细介绍

    目录 理论概述 Activity的理解 Activity的定义 Activity的作用 类比Activity与Servlet Intent的理解 Intent的分类 Intent的使用 IntentFilter的理解 相关的API 设置点击监听 Activity中添加监听 layout中添加监听 设置长按监听 Activity的开发 开发流程 Activity的使用  总结 理论概述 Activity的理解 Activity的定义 Activity,字面翻译为活动,他是Android定义的四大应

  • Android aapt自动打包工具详细介绍

    Android aapt自动打包工具 概念 在Android.mk中有LOCAL_AAPT_FLAGS配置项,在gradle中也有aaptOptions,那么aapt到底是干什么的呢? aapt即Android Asset Packaging Tool(Android 打包工具),在SDK的build-tools目录下.我们可以查 看,创建, 更新ZIP格式的文档附件(zip, jar, apk).也可将资源文件编译成二进制文件,尽管你可能没有直接使用过aapt工具,但是build script

  • Android 自定义View的构造函数详细介绍

     Android自定义View的构造函数 自定义View是Android中一个常见的需求,每个自定义的View都需要实现三个基本的构造函数,而这三个构造函数又有两种常见的写法. 第一种 每个构造函数分别调用基类的构造函数,再调用一个公共的初始化方法做额外初始化. public class MyView extends ListView { public MyView(Context context) { super(context); sharedConstructor(); } public

  • 基于Android Service 生命周期的详细介绍

    Service概念及用途: Android中的服务,它与Activity不同,它是不能与用户交互的,不能自己启动的,运行在后台的程序,如果我们退出应用时,Service进程并没有结束,它仍然在后台运行,那我们什么时候会用到Service呢?比如我们播放音乐的时候,有可能想边听音乐边干些其他事情,当我们退出播放音乐的应用,如果不用Service,我们就听不到歌了,所以这时候就得用到Service了,又比如当我们一个应用的数据是通过网络获取的,不同时间(一段时间)的数据是不同的这时候我们可以用Ser

  • Android中的Bitmap的详细介绍

    Bitmap简介(摘抄于网络) 位图文件(Bitmap),扩展名可以是.bmp或者.dib.位图是Windows标准格式图形文件,它将图像定义为由点(像素)组成,每个点可以由多种色彩表示,包括2.4.8.16.24和32位色彩. 例如,一幅1024×768分辨率的32位真彩图片,其所占存储字节数为:1024×768×32/(8*1024)=3072KB 位图文件图像效果好,但是非压缩格式的,需要占用较大存储空间,不利于在网络上传送.jpg/png格式则恰好弥补了位图文件的缺点. 在Android

随机推荐