App性能优化之View优化(2)——UI问题的解决

一.概况

上一篇中App性能优化之View优化(1)——UI问题的检测主要讲的是我们在写完代码之后,如何发现代码中的问题。从问题中提取经验,规范好自己之后的代码编写,本文就是讲如何规范的进行UI关联代码的书写。

二.主要的点

  • View控件的选择和布局文件层级优化;
  • Include,Merge,ViewStub等标签的使用;
  • 自定义View中关键步骤中减少耗时操作;
  • 非图片类型Drawable的使用;

三.View控件的选择和层级优化

3.1原则:

尽量较少层级;使用高效的VIew控件;

3.2选择View控件:

常用的控件有LinearLayout和RelativeLayout和ConstraintLayout和FrameLayout在他们中做出选择。
1.层级尽量减少:能用ConstraintLayout或者RelativeLayout来减少层级,不用LinearLayout;(ConstraintLayout较RelativeLayout有更高的效率推荐使用)
2.多层级时候,相同层级的用LinearLayout不用RelativeLayout;(前者在measure,layout的过程中有更好的效率,这里不展开说明,我们可以使用上一篇文章中Hierarchy View工具进行验证,查看measure,layout,draw的时间,有兴趣可以验证一下,这里不赘述)
3.作为容器控件的时候用FrameLayout;(单个的,如装Fragment的容器)

3.3去掉其他不必要的背景

3.3.1去掉window的默认背景

当我们使用了Android自带的一些主题时,window会被默认添加一个纯色的背景,这个背景是被DecorView持有的。当我们的自定义布局时又添加了一张背景图或者设置背景色,那么DecorView的background此时对我们来说是无用的,但是它会产生一次Overdraw,带来绘制性能损耗。
我们在Application层级或者Activity层级,在theme中更改windowbackground属性为null。

android:windowbackground="null"

3.3.2去掉其他不必要的背景

有时候为了方便会先给Layout设置一个整体的背景,再给子View设置背景,这里也会造成重叠,如果子View宽度mach_parent,可以看到完全覆盖了Layout的一部分,这里就可以通过分别设置背景来减少重绘。或者子View没有要求背景,那么给父VIew添加了背景就可以了。

四.Include,Merge,ViewStub等;

4.1Include标签来进行布局复用

多个页面拥有相同的局部布局的时候,并且这部分布局改动的可能性较小或者不动,那么就用Include标签。

4.2用Merge标签去除多余层级

Merge意味着合并,在合适的场景使用Merge标签可以减少多余的层级。Merge标签一般和Include标签搭配使用,适合使用的场景:

  • merge标签最好是来替代FrameLayout;
  • 布局方向一致的LinearLayout,比如当前父布局LinearLayout的布局方向是垂直的,包含的子布局LinearLayout的布局方向也是垂直的,则可以用merge标签来替换子布局LinearLayout;

4.3使用ViewStub来提高加载速度

使用场景:

一个很常见的开发场景就是我们想要一个布局时,并不是所有的控件都需要显示出来,而是显示出一部分,对于这种情况,我们一般采用的方法就是使用View的GONE和INVISIBLE,但是这种方法效率不高,虽然是达到了隐藏的目的,但是仍在布局当中,系统仍然会解析它们,我们可以用ViewStub来解决这一问题。

ViewStub的优势

ViewStub是轻量级的View,不可见并且不占布局位置。当ViewStub调用inflate方法或者设置可见时,系统会加载ViewStub指定的布局,然后将这个布局添加到ViewStub中,在对ViewStub调用inflate方法或者设置可见之前,它是不占布局空间和系统资源的,它主要的目的就是为目标视图占用一个位置。因此,使用ViewStub可以提高界面初始化的性能,从而提高界面的加载速度。

使用

ViewStub的内容布局文件title_bar

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:text="Back"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Title"/>
</RelativeLayout>

ViewStub所在的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <ViewStub
        android:id="@+id/vs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/title_bar"/>

</LinearLayout>

使用代码

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewStub vs = findViewById(R.id.vs);
        //vs.inflate();
        vs.setVisibility(View.VISIBLE);
    }

要注意的点

  1. ViewStub只能加载一次,加载后ViewStub对象会被置为空,这样当ViewStub引用的布局被加载后,就不能用ViewStub来控制引用的布局了。因此,如果一个控件需要不断的显示和隐藏,还是要使用View的Visibility属性。
  2. ViewStub不能嵌套Merge标签。
  3. 上面的inflate和setVisiblity方法都可以。

4.4clipRect的使用

我们可以通过canvas.clipRect()来 帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。这个API可以很好的帮助那些有多组重叠 组件的自定义View来控制显示的区域。同时clipRect方法还可以帮助节约CPU与GPU资源,在clipRect区域之外的绘制指令都不会被执行,那些部分内容在矩形区域内的组件,仍然会得到绘制。

4.5非图片Drawable的使用

使用场景:

在一些View的背景为纯色或者已知渐变色的时候我们尽量用非图片Drawable代替切图,这样带来的好处是可以减小Apk的大小。

使用方法:

  1. 作为View的纯色背景(使用shape);
  2. 作为点击变色Button的纯色背景(selecter);

猜你喜欢

转载自blog.csdn.net/gongxiaoou/article/details/81478049