您的位置:首页 > 移动开发 > Android开发

android 视图性能优化

2016-08-04 17:59 148 查看

android视图性能优化

1.视图性能

(1)Overdraw简介

    Overdraw就是过度绘制,是指在一帧的时间内(16.67ms)像素被绘制了多次,理论上一个像素每次只绘制一次是最优的,但是由于重叠的布局导致一些像素会被多次绘制,而每次绘制都会对应到CPU的一组绘图命令和GPU的一些操作,当这个操作耗时超过16.67ms时,就会出现掉帧现象,表现为应用卡顿,所以对重叠不可见元素的重复绘制会产生额外的开销,需要尽量减少Overdraw的发生。

(2)Overdraw检测

    Android提供了测量Overdraw的选项,在开发者选项-调试GPU过度绘制(Show
GPU Overdraw),打开选项就可以看到当前页面Overdraw的状态,就可以观察屏幕的绘制状态。

提高程序在视图方面的性能,总的原则就是:尽量避免重叠不可见元素的绘制。

(3)Overdraw改良

1)合理选择控件容器

    Android提供的Layout控件主要包括 LinearLayout、TableLayout、FrameLayout、RelativeLayout。同一个界面可以使用不同的容器控件来表达,但是各个容器控件描述界面的复杂度是不一样的。一般来LinearLayout最易,RelativeLayout较复杂。
LinearLayout只能用来描述一个方向上连续排列的控件,而RelativeLayout几乎可以用于描述任意复杂度的界面。。综上所述: LinearLayout易用,效率高,表达能力有限。RelativeLayout复杂,表达能力强,效率低。从减少overdraw的角度来看,LinearLayout会增加控件数的层级,自然是RelativeLayout
更优,但是当某一界面在使用LinearLayout并不会比RelativeLayout带来更多的控件数和控件层级时,LinearLayout则是首选。

2)去掉window的默认背景

    当使用Android自带的一些主题时,window会被默认添加一个纯色的背景,这个背景是被DecorView持有的。当自定义布局时又添加了一张背景图或者设置背景色,那么DecorView的background此时是无用的,但是它会产生一次Overdraw,带来绘制性能损耗。去掉window的背景可以在onCreate()中setContentView()之后调用getWindow().setBackgroundDrawable(null);或者在theme中添加
android:windowbackground="null"。

3)去掉其他不必要的背景

    父容器若已经有了背景,可不设置对应子控件的背景,及大的布局背景已经设置,应避免设置局部重复的背景。

4)自定义View处理

    对于自定义的view视图,可以通过canvas.clipRect()来帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。这个API可以很好的帮助那些有多组重叠组件的自定义View来控制显示的区域。同时clipRect方法还可以帮助节约CPU与GPU资源,在clipRect区域之外的绘制指令都不会被执行,那些部分内容在矩形区域内的组件,仍然会得到绘制。除了clipRect方法之外,我们还可以使用canvas.quickreject()来判断是否没和某个矩形相交,从而跳过那些非矩形区域内的绘制操作。

5)ViewStub高效占位符

    当遇到这样的情况,运行时动态根据条件来决定显示哪个View或布局。常用的做法是把View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改它的可见性。这种模式的缺点是耗费资源。虽然把View
的初始View.GONE但是在Inflate布局的时候View仍然会被Inflate,程序运行时仍然会创建对象,会被实例化,会被设置属性,会耗费内存等资源。

    推荐的做法是使用android.view.ViewStub,ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还是不要显示某个布局。

6)善用draw9patch

    给ImageView加一个边框,通常在ImageView后面设置一张背景图,露出边框便完美解决问题,此时这个ImageView,设置了两层drawable,两层drawable的重叠区域去绘制了两次,导致
overdraw。优化方案:将背景drawable制作成draw9patch,并且将和前景重叠的部分设置为透明。由于Android的2D渲染器会优化draw9patch中的透明区域,从而优化了这次overdraw。

7)Merge 

    使用Merge标签来做容器控件。第一种子视图不需要指定任何针对父视图的布局属性,就是说父容器仅仅是个容器,子视图只需要直接添加到父视图上用于显示就行。另外一种是假如需要在LinearLayout里面嵌入一个布局(或者视图),而恰恰这个布局(或者视图)的根节点也是LinearLayout,这样就多了一层没有用的嵌套,无疑这样只会拖慢程序速度。而这个时候如果我们使用merge根标签就可以避免那样的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息