HierarchyViewer分析UI性能;GPU过度绘制分析UI性能;使用Memory监测及GC打印与Allocation Tracker进行UI卡顿分析;运行DDMS->Allocation Tracker;使用Traceview和dmtracedump进行分析优化;使用Systrace进行分析优化;使用traces.txt文件进行ANR分析优化。
性能优化有那几个方面:一、内存优化。二、UI优化(布局优化和绘制优化)。三、速度的优化(线程优化/网络优化)。四、电量优化。五、启动优化。
APP性能指标:安全、启动时间;CPU占用;内存占用;流量;电量。
1. 提速,启动优化;
2. App瘦身;
3.UI优化(布局优化和绘制优化);
> App提速,启动优化,优化App启动时间
App启动优化最佳实践-
给 App 提速:Android 性能优化总结: http://android.jobbole.com/81944/
冷启动实现APP秒开- http://mp.weixin.qq.com/s/XQYgYP-OkEEtHsprmaMF_w
android 提高App启动速度--
Android开机启动速度优化 && app启动速度优化--
为Android启动加速--
Android性能优化第(八)篇---App启动速度优化上-
应用启动速度优化布局方案,这个框架对于界面复杂的启动逻辑有效果,不是把整个项目都用这种方式处理,那么无形中增加了很多中间类,同时兼容性也不一定好。我们的目的就是为了启动速度优化而已。核心技术就是利用注解处理器在编译期间提前生成控件类。
掌阅公司X2C框架Android Increase layout loading speed 200%- https://github.com/iReaderAndroid/X2C
性能优化之启动优化-优化方向:Application和Activity启动流程。
-- App加速启动 和 加速启动首个Activity:加速启动App,也包括加速启动LaunchActivity
1.App加速启动:优化多进程导致Application多次启动,延迟加载第三方库等,在线程中启动第三方jar aar包等;
2.加速启动Activity
a.减少onCreate的时间,耗时操作
b.移除背景
c.在很多的应用一开始点击的时候总会出现黑屏或者白屏,甚至前段时间微信也有同样的问 题。其实白屏或者黑屏还是一些其他的东西,都是因为 Android 主题的问题,只要自己自 定义一个启动主题,问题完美解决
-- APP 启动优化-
- APP 启动黑白屏问题
<item name="android:windowDisablePreview">true</item>
<item name="android:windowBackground">@null</item>
单独做成一个 AppTheme.Launcher
<style name="AppTheme.Launcher">
<item name="android:windowFullscreen">true</item>
<!--<item name="android:windowDisablePreview">true</item>-->
<item name="android:windowBackground">@color/colorAccent</item>
</style>
- Appcation 中优化方案(并不绝对,优化思路差不多)
开子线程,线程中没有创建 Handler、没有操作 UI 、对异步要求不高
懒加载,用到的时候在初始化,如网络,数据库,图片库,或一些三方库。
使用 IntentService onHandleIntent () 方法来进行初始化一些比较耗时的操作
//开始计时
Debug.startMethodTracing(filePath);
... 中间为需要统计执行时间的代码
//停止计时
Debug.stopMethodTracing();
-- 启动页加速
其实你不知道MultiDex到底有多坑-
异步MultiDex方案,MultiDex拖慢App启动。
这种方案也是目前比较流行的Dex手动分包方案,启动App的时候,先显示一个简单的Splash闪屏界面,然后启动Worker线程执行MultiDex#install(Context)工作,就可以避免UI线程阻塞。不过要确保启动以及启动MultiDex#install(Context)所需要的类都在主dex里面(手动分包),而且需要处理好进程同步问题。
Application开始到首页显示出来,这个过程,我们应该注意一些什么,将这个过程细分一下,会有下面的时间点需要注意。Application的构造器方法—>attachBaseContext()—>onCreate()—>Activity的构造方法—>onCreate()—>配置主题中背景等属性—>onStart()—>onResume()—>测量、布局、绘制显示在界面上。
第一种写法:直接PostDelay 300ms.myHandler.postDelayed(mLoadingRunnable, DEALY_TIME);
第二种写法:优化的DelayLoad
getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
myHandler.post(mLoadingRunnable);
}
});
> APK瘦身
关于APK瘦身值得分享的一些经验 http://zmywly8866.github.io/2015/04/06/decrease-apk-size.html
Android 应用瘦身实践,从 18MB 到 12.5MB- http://www.codeceo.com/article/android-18mb-to-12mb.html
Android性能优化之APK瘦身详解(瘦身73%)- https://www.jianshu.com/p/fee82949ff84
优化工作的冰山一角,app瘦身- http://mp.weixin.qq.com/s?__biz=MzI2OTQxMTM4OQ==&mid=2247484570&idx=1&sn=56eea8a80c79b25a2e192e0017091cc3&chksm=eae1f1c8dd9678debb68ffc78ec3b1a9fbb8f8b70107164a77e85fc16c81157cabcb384c213c#rd 如何给你的Android 安装文件(APK)瘦身- http://android.jobbole.com/80613/
-- 支付宝 App 构建优化解析:Android 包大小极致压缩- https://mp.weixin.qq.com/s/m9HiZv6HoFEcxg8nHTCLeg 支付宝关于包大小优化,支付宝一直在这个方向上努力,因此我们引入了很多方案,比如 “proguard 代码混淆”,“图片从 png 到 tinypng 到 webp”,“引入 7zip 压缩方案”等。
JVM 运行时加载的是 .class 文件,Android 为了使包大小更紧凑,并且运行更高效发明了 dalvik 和 art 虚拟机,两种虚拟机运行的都是 .dex 文件(当然 art 虚拟机还可以同时运行 oat 文件,不在本文章讨论范围)。
所以 dex 文件里面信息的内容和 class 文件包含的信息是完全一致的,不同的是 dex 文件对 class 中的信息做了去重,一个 dex 包含了很多的 class 文件,并且在结构上有比较大的差异,class 是流式的结构,dex 是分区结构,各个区块间通过 offset 索引。后面就只提 dex 的结构。
其实在 proguard 的时候就是有配置可以去掉或保留这个行号信息,-keep SourceFile, LineNumberTable 就是这个作用,为了方便定位问题,基本所有的开发都保留了这个配置。
移动开发平台(Mobile PaaS,简称 mPaaS)是源于支付宝 App 的移动开发平台,为移动开发、测试、运营及运维提供云到端的一站式解决方案,能有效降低技术门槛、减少研发成本、提升开发效率,协助企业快速搭建稳定高质量的移动 App。https://tech.antfin.com/docs/2/49549
熟悉Activity启动流程的朋友都知道,Activity 的启动是在 ActivityThread 里完成的,handleLaunchActivity() 会依次间接的执行到 Activity 的 onCreate(), onStart(), onResume()。在执行完这些后 ActivityThread 会调用 WindowManager#addView(),而这个 addView()最终其实是调用了 WindowManagerGlobal 的 addView() 方法 。
最近Facebook开源了Redex Redex是Andoird字节码(DEX)优化工具 被Redex优化过后的APK体积更小 运行速度更快
Redex 基于管道的方式来优化Android 的.dex文件,一个源 .dex文件通过管道进行一系列的自定义转换后,将得到一个优化的 .dex 文件.https://github.com/facebook/redex
- 携程 App Size 大小优化相关
1.通过脚本或第三方工具检测删除无用的资源、类、函数;
2.通过 Sonar 检测整个 App 中的重复代码,将重复代码合并或 App 删除;
3.清理第三方引入的库,删除不用的多套库,比如百度和高德地图 SDK 等,多套图片库等;
4.不轻易引进第三方的库,比如注解框架等,慎重使用第三方定义的控件,自己自定义控件去实现;
5.关于资源图片统一经过 tinpng 压缩;
6.资源图片统一整理,功能和资源统一,不重复造轮子,删除原来的多套资源;
7.资源图片使用 SVG 或者 WebP 格式图片去替换;
8.清理高清资源大图片,特别是超过 10K 以上的图片;
9.能用代码去实现的 UI,尽量不用去图片代替;
10.Native 转 H5;
11.Native 或者 H5 转 React Native;
12.Hybrid 页面离线的 JS 资源,直接转换成 RN,减少包大小比较明显。
shape代替图片,减小APP size;
Vector:通常在Android中使用,只实现了SVG语法中的path标签,可以视为简单化的矢量图。
ProGuard是一个压缩、优化和混淆Java字节码的工具,在一定程度可以减少App size.
- 缩减APK包大小
1.保持良好的编程习惯,不要重复或者不用的代码,谨慎添加libs,移除使用不到的libs,使用proguard混淆代码,它会对不用的代码做优化,并且混淆后也能够减少安装包的大小
2.使用Lint工具查找没有使用到的资源。去除不使用的图片,String,XML等等
3.能用代码绘制实现的功能,尽量不要使用大量的图片
> UI优化( UI层级不要过多 )
Android性能优化系列之布局优化-
Android UI性能优化实战 识别绘制中的性能问题--
性能优化之布局优化- http://www.trinea.cn/android/layout-performance/ Android UI性能优化 检测应用中的UI卡顿-- Hierarchy Viewer 分析UI性能
减少不必要的层次:巧用Hierarchy Viewer. 优化:http://www.2cto.com/kf/201411/348847.html
Android的官方文档中,有这么一句话:出于安全考虑,Hierarchy Viewer只能连接Android开发版手机或是模拟器。
通过Hierarchy Viewer去检测渲染效率,去除不必要的嵌套;
-- UI 优化
1.造成卡顿的原因
2.如何分析当前页面绘制情况
- 使用GPU过度绘制检测页面渲染层级
- 使用Layout Inspector查看布局层级
3.如何优化
- 移除叠加的背景
- 合理使用布局设计
- 采用布局标签减少布局嵌套
include和merge的用法
ViewStub的用法
在SDK以前的旧版本,是可以通过Hierarchy Viewer来查看,但后面更新了版本,Google采用Layout Inspector来代替Hierarchy Viewer,详见 Android SDK Tools Revision 25.3.0。
在不增加页面层级的情况下,可以用FrameLayout和LinearLayout代替RelativeLayout实现,但是RelativeLayout也有它的优点,利用它的各种相对属性可以减少我们的页面层级,所以总的来说就是,如果能减少页面层级可以考虑采用RelativeLayout,如果是相同层级的情况下,优先考虑采用FrameLayout和LinearLayout。
另外,很多时候我们为了方便喜欢在LinearLayout中,采用它的layout_weight来为子View设置显示的比例,但是layout_weight同样会触发LinearLayout测量两遍,所以慎用。
Android性能优化手册』布局分析与调优- https://www.jianshu.com/p/809f95341695
Android LayoutInflater.inflate各个参数作用了解一下?- https://www.jianshu.com/p/3f871d95489c
-- UI渲染
人眼与大脑之间的协作无法感知超过60fps的画面更新。12fps大概类似手动快速翻动书籍的帧率,这明显是可以感知到不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果。24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的减少费用支出。但是低于30fps是 无法顺畅表现绚丽的画面内容的,此时就需要用到60fps来达到想要的效果,当然超过60fps是没有必要的(据说Dart能够带来120fps的体验)。开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms=1000/60的时间。
Android系统每隔16ms就会重新绘制一次Activity View。因为Android系统每隔16ms就会发出VSYNC信号,触发对UI进行渲染,VSYNC是Vertical Synchronization(垂直同步)的缩写,可以简单的把它认为是一种定时中断。在Android 4.1中开始引入VSYNC机制。如果操作不能在 16 ms 内完成,那它则不能赶上这次的绘制公交车,只能等下一轮,这种现象叫做 “掉帧”,用户看到的就是界面绘制不连续、卡顿。 16ms的时间主要被两件事情占用,第一件:将UI对象转换为一系列多边形和纹理;第二件:CPU传递处理数据到GPU进行栅格化,因此要缩短这两部分的时间,需要尽力减少对象转换的次数以及可能发声的问题和解决方案。
了解Android是如何利用GPU进行画面渲染有助于我们更好的理解性能问题。一个很直接的问题是:activity的画面是如何绘制到屏幕上的?那些复杂的XML布局文件又是如何能够被识别并绘制出来的?Resterization栅格化是绘制那些Button,Shape,Path,String,Bitmap等组件最基础的操作。它把那些组件拆分到不同的像素上进行显示。这是一个很费时的操作,GPU的引入就是为了加快栅格化的操作。
渲染操作通常依赖于两个核心组件:CPU与GPU。CPU负责把UI组件计算成Polygons,Texture纹理,(负责包括Measure,Layout,Record,Execute的计算操作,CPU把控件进行多边形化和纹理化);然后交给GPU进行栅格化渲染。然而每次从CPU转移到GPU是一件很麻烦的事情,所幸的是OpenGL ES可以把那些需要渲染的纹理Hold在GPU Memory里面,在下次需要渲染的时候直接进行操作。所以如果你更新了GPU所hold住的纹理内容,那么之前保存的状态就丢失了。
CPU方法,最常见的性能问题是不必要的布局和失效,这些内容必须在识图层次结构中进行测量,清除并重新创建,引发这种问题通常的原因通常有两个,一个是重建显示列表的次数太多,而是花费太多时间作废视图层次并进行不必要的重绘,这两个原因在更新显示列表或者其他缓存GPU资源时资源时导致CPU工作过度。( CPU通常存在的问题的原因是存在非必需的视图组件,它不仅仅会带来重复的计算操作,而且还会占用额外的GPU资源。)
而GPU方法,最常见的问题就是过度绘制,通常实在像素着色过程中,通过其他工具进行后期着色时浪费了GPU处理时间。因此,对UI优化时,可以重点从以下两个方向进行:
1.CPU产生的问题:不必要的布局和失效;
2.GPU产生的问题:过度绘制(overdraw);
在Android里面那些由主题所提供的资源,例如Bitmaps,Drawables都是一起打包到统一的Texture纹理当中,然后再传递到GPU里面,这意味着每次你需要使用这些资源的时候,都是直接从纹理里面进行获取渲染的。当然随着UI组件的越来越丰富,有了更多演变的形态。例如显示图片的时候,需要先经过CPU的计算加载到内存中,然后传递给GPU进行渲染。文字的显示比较复杂,需要先经过CPU换算成纹理,然后交给GPU进行渲染,返回到CPU绘制单个字符的时候,再重新引用经过GPU渲染的内容。动画则存在一个更加复杂的操作流程。
为了能够使得App流畅,我们需要在每帧16ms以内处理完所有的CPU与GPU的计算,绘制,渲染等等操作。 Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次重叠的UI结构里面,如果不可见的UI也在做绘制的操作,会导致某些像素区域被绘制了多次。这样就会浪费大量的CPU以及GPU资源。
有了对Android渲染机制基本的认识以后,那么我们的卡顿的原因就在于没有办法在16ms内完成该完成的操作,而主要因素是在于没有必要的layouts、invalidations、Overdraw。渲染的过程是由CPU与GPU协作完成.
Android需要把XML布局文件转换成GPU能够识别并绘制的对象。这个操作是在DisplayList的帮助下完成的。DisplayList持有所有将要交给GPU绘制到屏幕上的数据信息。在某个View第一次需要被渲染时,Display List会因此被创建,当这个View要显示到屏幕上时,我们会执行GPU的绘制指令来进行渲染。
如果View的Property属性发生了改变(例如移动位置),我们就仅仅需要Execute Display List就够了。然而如果你修改了View中的某些可见组件的内容,那么之前的DisplayList就无法继续使用了,我们需要重新创建一个DisplayList并重新执行渲染指令更新到屏幕上。
请注意:任何时候View中的绘制内容发生变化时,都会需要重新创建DisplayList,渲染DisplayList,更新到屏幕上等一系列操作。这个流程的表现性能取决于你的View的复杂程度,View的状态变化以及渲染管道的执行性能。举个例子,假设某个Button的大小需要增大到目前的两倍,在增大Button大小之前,需要通过父View重新计算并摆放其他子View的位置。修改View的大小会触发整个HierarcyView的重新计算大小的操作。如果是修改View的位置则会触发HierarchView重新计算其他View的位置。如果布局很复杂,这就会很容易导致严重的性能问题。
通过Show GPU Overdraw去检测Overdraw,最终可以通过移除不必要的背景以及使用canvas.clipRect解决大多数问题。
Overdraw 的处理方案一:移除不必要的background;
Overdraw 的处理方案二:clipRect的妙用;
-- 过度绘制优化步骤如下:
1. 移除Window默认的Background;
2. 移除XML布局文件中非必需的Background;
3. 按需显示占位背景图片;
通过clipRect来解决自定义View的过度绘制,提高自定义View的绘制性能.
-- 如何避免Overdraw
合理选择控件容器:LinearLayout易用,效率高,表达能力有限。RelativeLayout复杂,表达能力强,效率稍逊
去掉window的默认背景:可以在onCreate()中setContentView()之后调用getWindow().setBackgroundDrawable(null);或者在theme中添加android:windowbackground="null";
去掉其他不必要的背景
ViewStu延时加载布局
Merge减少层级的嵌套
-- 通常来说,针对自定义View,我们可能犯下面三个错误:
1.Useless calls to onDraw():我们知道调用View.invalidate()会触发View的重绘,有两个原则需要遵守,第1个是仅仅在View的内容发生改变的时候才去触发invalidate方法,第2个是尽量使用ClipRect等方法来提高绘制的性能。
2.Useless pixels:减少绘制时不必要的绘制元素,对于那些不可见的元素,我们需要尽量避免重绘。
3.Wasted CPU cycles:对于不在屏幕上的元素,可以使用Canvas.quickReject把他们给剔除,避免浪费CPU资源。另外尽量使用GPU来进行UI的渲染,这样能够极大的提高程序的整体表现性能。
时刻牢记,尽量提高View的绘制性能,这样才能保证界面的刷新帧率尽量的高。
-- Android UI优化,布局优化:merge,ViewStub,include
1.layout组件化,尽量使用merge及include复用
2.使用styles,复用样式定义
3.软键盘的弹出控制,不要让其覆盖输入框
4.数字、字母和汉字混排占位问题:将数字和字母全角化。由于现在大多数情况下我们的输入都是半角,所以 字母和数字的占位无法确定,但是一旦全角化之后,数字、字母的占位就和一个汉字的占位相同了,这样就可以避免由于占位导致的排版问题。
5.英文文档排版:textview自动换行时要保持单词的完整性,解决方案是计算字符串长度,然后手动设定每一行显示多少个字母并加上‘n
6.复杂布局使用RelativeLayout
7.自适应屏幕,使用dp替代pix
8.使用android:layout_weight或者TableLayout制作等分布局
9.使用animation-list制作动画效果