总结归纳自《Android开发艺术探索》、《Android群英传》等关于性能优化资料。
转载请注明链接:http://blog.csdn.net/feather_wch/article/details/79615455
Android性能优化
版本: 2018/3/20-1
1、UI渲染机制
- 系统通过VSYNC信号触发对UI的渲染、重绘,其间隔时间是16ms。
- 这个16ms其实就是1000ms显示60帧画面的单位时间
- 如果不能在16ms内完成绘制,那么就会造成丢帧现象。会在下个信号才开始绘制(2*16ms)—导致卡顿
布局优化
2、布局优化的思想
- 减少布局文件层级
- 使用高性能布局
3、View是什么?
- View是Android系统在屏幕上的视觉呈现.
- View是一种控件
4、View是怎么绘制出来的?
- View的绘制流程是从ViewRoot的performTraversals()方法开始
- measure()
- layout()
- draw()
5、View是怎么呈现在界面上的?
- Android中的视图都是通过Window来呈现的(Activity、Dialog还是Toast都有一个Window)
- 然后通过WindowManager来管理View。
- Window和顶级View——DecorView的通信是依赖ViewRoot完成的。
6、View和ViewGroup什么区别?
- View是所有控件和布局的父类。
ViewGroup
也属于View
,构成一种树状结构
7、视图优化的几种方法
- 减少画面绘制的时间
- 避免过度绘制
- 优化布局层级
- 避免嵌套过多无用布局
8、RelativeLayout和LinearLayout的性能差异
- 两者
layout和draw
性能相等,区别在于measure
过程RelativeLayout
对所有子View
会进行两次measure(横向+纵向)
—因为子View
间可能同时有纵向和横向的依赖关系
,所有都需要进行一次测量。LinearLayout
会进行一次measure
,如果有weight属性
才会进行第二次measure
9、布局的选择
- 如果不涉及到
层级深度
,应该选择高效的LinearLayout或者FrameLayout
- 涉及到层级深度时,如
ListView
中更适合使用RelativeLayout
,且尽可能使用pading
代替margin
ConstraintLayout
是性能最好的布局!
10、布局层级优化的三种方法
include
标签merge
标签ViewStub
11、include标签的特点和使用方法
include
主要是用于布局重用,就不需要重复写相同的布局include
中只支持layout_
开头的属性,如果指定了id
则会覆盖掉所包含的布局文件根元素的id属性
//main.xml
<android.support.constraint.ConstraintLayout ...>
<include
android:id="@+id/include"
layout="@layout/my_include_layout"
android:layout_width="200dp"
android:layout_height="200dp"
.../>
<TextView
android:id="@+id/sample_text"
... />
</android.support.constraint.ConstraintLayout>
//my_include_layout.xml
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
.../>
</android.support.constraint.ConstraintLayout>
12、merge标签的作用
merge
一般配合include标签
使用,用于减少布局层级
- 假如
include标签
外层是LinearLayout
,内部布局根元素的布局也是LinearLayout
,使用merge
能减少不必要的层级。
//需要将include所包含的内部布局的根布局使用merge标签,如my_include_layout.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I'm include"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</merge>
13、ViewStub的作用和使用
- 轻量级组件(继承View):不可视、大小为0
ViewStub
一旦进行显示,就不存在了,取而代之的是被inflate的布局,并将ID设置为ViewStub中android:inflateid
属性所指的ID,因此两次调用inflate
方法会报错ViewStub
还不支持merge标签
<ViewStub
android:id="@+id/not_often_use"
......
android:layout="@layout/not_often_use"/>
//1. 获得ViewStub组件
mViewStub = (ViewStub)findViewById(R.id.not_often_use); //viewstub的ID
//2-1. 显示该View的第一种方法
mViewStub.setVisibility(View.VISIBLE)
//2-2. 显示该View的第二种方法
View flateView = mViewStub.inflate();
TextView textview = (TextView)inflateView.findViewById(R.id.tv);
14、绘制优化-优化View的onDraw方法
onDraw
中不要创建新的局部对象
—onDraw
可能会频繁调用,瞬间创建大量对象和大量GConDraw
中不要做耗时的任务,尽量要保证View的绘制频率60fps(每帧画面不超过16ms)
内存优化
15、内存泄漏优化
静态变量
所导致的内存泄漏:如Activity内部静态变量持有Activity的this等单例模式
导致的内存泄漏:单例模式的对象中的链表等持有了如:Activity的this指针
,却没有即使释放会导致泄露,因为单例的特点是其生命周期和Applicaiton
一致。属性动画
不停止会导致内存泄漏:无限循环动画会持有Activity的View
,而View
持有了Activity
,最终导致泄露。解决办法是在onDestory
中调用animator.cancel()
16、ANR是什么?
- UI线程执行耗时操作会导致ANR
- 如果
BroadcastReceiver
10秒没有执行完操作,就会导致ANR
17、ANR如何分析?
- 只要出现
ANR
,系统都会在/data/anr/目录
下生成相应的trace.txt
- 根据内容可以分析
ANR
的具体原因
18、ANR出现的几种特殊情况
主线程UI线程
中进行耗时操作
UI线程
和在其他线程的耗时操作
竞争同一个锁。
19、ListView/GridView的优化
- 采用
ViewHolder
- 避免在
getView
中执行耗时操作- 根据滑动状态控制任务的
执行频率
,避免快速滑动时开启大量的异步操作。- 开启硬件加速,使列表滑动更流畅。
20、Bitmap的优化
- 选择合适大小图片, 也可以在图片列表时显示缩略图,显示图片的时候使用原图
- 通过
BitmapFactory.Options
对图片进行采样、- 图片缓存-使用
内存缓存LruCache
和硬盘缓存DiskLruCache
21、线程优化
- 采用线程池,避免线程的创建和销毁带来的性能损失
- 线程池能有效控制最大并发数,避免抢占资源导致的阻塞
22、性能优化建议
- 避免创建过多的对象
- 不要过多使用枚举,枚举所占空间比整数大。少用迭代器。
- 常量使用
static final
进行修饰- 使用
Andorid特有的数据类型
,如SparseArray和Pair
,性能更好。- 适当使用
软引用
和弱引用
- 采用内存缓存和硬盘缓存
- 尽量使用静态内部类,避免由于内部类导致的内存泄露
- 使用静态方法,静态方法会比普通方法提高15%的访问速度
- 减少不必要的成员变量,这点在Android Lint工具上已经集成检测了,如果一个变量可以定义为局部变量,则会建议你不要定义成成员变量。
- 减少不必要的对象,使用基础类型会比使用对象更加节省资源,同时更应该避免频繁创建短作用域的变量。
- 对Cursor、Receiver、Sensor、File等对象,要非常注意对它们的创建、回收与注册、解注册
- 避免使用IOC框架,IOC通常使用注解、反射来实现,虽然Java已经进行了很好的优化,但大量使用反射依然会带来性能的下降。
- 使用RenderScript、OpenGL进行复杂的绘图操作。
- 使用SurfaceView代替View进行大量、频繁的绘图操作。
- 尽量使用视图缓存,而不是每次都执行inflate()方法解析视图。
22、性能优化工具汇总
- UI渲染时间工具:开发者中选择
Profile GPU Rendering(GPU呈现模式分析)
,选择On Screen as bars
能开启条形图。蓝色线条
为绘制的时间,要控制在绿线之下。- 过度绘制:开发者中
Enable GPU OverDraw(开启过度绘制检查)
- 布局层级:
Hierarchy Viewer
,在Android Device Monitor
中使用。- 代码提示工具:Lint
- Memory Monitor
- TraceView日志
- MAT
- Dumpsys
- Memory Info