Android性能优化1

1.布局优化
2.绘制优化
3.响应速度优化和ANR日志分析

布局优化

布局优化思想就是,尽量减少布局文件的层级,以便减少android绘制的工作量.

删除无用的控件和层级,如果在相同层级的情况下,尽量用LinearLayout.而不用RelativeLayout.一个View能展示出来,需要依次经过measure,layout和draw三个过程才最终将一个View绘制出来,而两者过程存在不同的差异

RelativeLayout
因为RelativeLayout允许A,B 2个子View,横向上B依赖A,纵向上A依赖B。所以RelativeLayout在onMeasure测量子控件的时候,会对子View做两次measure(需要横向纵向分别进行一次排序测量)

LinearLayout
LinearLayout会先判断线性规则,然后执行对应方向上的测量

1.RelativeLayout会让子View调用2次onMeasure,LinearLayout 在有weight时,也会调用子View2次onMeasure
2.RelativeLayout的子View如果高度和RelativeLayout不同,则会引发效率问题,当子View很复杂时,这个问题会更加严重。如果可以,尽量使用padding代替margin。
3.在不影响层级深度的情况下,使用LinearLayout和FrameLayout而不是RelativeLayout。Google给开发者默新建了个RelativeLayout,而自己却在DecorView中用了个LinearLayout。因为DecorView的层级深度是已知而且固定的,上面一个标题栏,下面一个内容栏。采用RelativeLayout并不会降低层级深度,所以此时在根节点上用LinearLayout是效率最高的。而之所以给开发者默认新建了个RelativeLayout,是希望开发者能采用尽量少的View层级来表达布局以实现性能最优,因为复杂的View嵌套对性能的影响会更大一些。

使用标签复用布局,include只支持android:layout_开头的属性
使用标签减少布局层级




    ...

Android性能优化1_第1张图片
不使用merge



    ...

使用merge

在布局根节点和上一级布局根节点相同的情况下,使用merge标签会减少布局层级

使用ViewStub



加载的两种方式:

((ViewStub)findViewById(R.id.view_stub)).setVisibility(View.VISIBLE);
View view = ((ViewStub)findViewById(R.id.view_stub)).inflate();

当ViewStub被加载完成之后,就会被内部的布局替换掉,这个时候ViewStub就不是布局的一部分了ViewStub不支持merge标签

绘制优化

绘制优化即是在View的onDraw方法要避免大量的操作.

不要在onDraw里面创建对象,因为onDraw可能会被频繁调用,导致产生大量的临时对象,占用过多的内存,也会导致系统更加频繁的gc ,降低程序的执行效率
不要做耗时的任务,不要执行成千上万的循环操作,大量的循环会抢占CPU的时间片,导致view的绘制过程不顺畅

响应速度优化和ANR日志分析

响应速度优化的思想是避免在主线程做耗时操作,响应速度慢,一般体现在Activity的启动速度上,如果主线程做太多事情,会导致Activity启动时出现黑屏现象,甚至出现ANR.
android规定,Activity如果5秒无法响应屏幕触摸事件,或者键盘输入事件,就会出现ANR,BroadcastReceiver如果10秒还未执行完操作也会出现ANR

当出现ANR,系统会在/data/anr/目录下创建一个文件traces.txt
adb pull traces.txt导出文件,查看ANR的原因

模拟ANR 主线程耗时操作

在onCreate方法中耗时操作.
setContentView(R.layout.activity_test_anr);
        findViewById(R.id.anr_test).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SystemClock.sleep(30000);
            }
        });

然后导出traces.txt文件,并且找到本应用的信息

----- pid 28803 at 2017-10-09 17:17:12 -----
Cmd line: 这里是应用的包名

JNI: CheckJNI is off; workarounds are off; pins=0; globals=271

DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0)

"main" prio=5 tid=1 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 obj=0x415baca8 self=0x414f3580
  | sysTid=28803 nice=0 sched=0/0 cgrp=apps handle=1074295124
  | state=S schedstat=( 0 0 0 ) utm=31 stm=31 core=6
  at java.lang.VMThread.sleep(Native Method)
  at java.lang.Thread.sleep(Thread.java:1013)
  at java.lang.Thread.sleep(Thread.java:995)
  at android.os.SystemClock.sleep(SystemClock.java:115)
  at 应用包名.TestANRActivity$1.onClick(TestANRActivity.java:18)
  at android.view.View.performClick(View.java:4445)
  at android.view.View$PerformClick.run(View.java:18429)
  at android.os.Handler.handleCallback(Handler.java:733)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:136)
  at android.app.ActivityThread.main(ActivityThread.java:5001)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:515)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:736)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:570)
  at dalvik.system.NativeStart.main(Native Method)

可以看到是在应用包名.TestANRActivity$1.onClick然后调用了SystemClock.sleep方法导致的ANR.

模拟ANR同步锁,等待

findViewById(R.id.anr_test).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        testANR();
                    }
                }).start();

                SystemClock.sleep(10);//延迟10毫秒,确保先执行子线程获得锁
                init();
            }
        });
    }
    private synchronized void testANR() {
        SystemClock.sleep(30*10000);
    }
    private synchronized void init() {

    }

先让testANR()方法获取到锁,然后init()方法再去获取相同的锁,但是锁被testANR()同步住了,导致子线程和主线程抢占同步锁,发生ANR

----- pid 24899 at 2017-10-09 17:35:10 -----
Cmd line:应用包名

JNI: CheckJNI is off; workarounds are off; pins=0; globals=271

DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0)

"main" prio=5 tid=1 MONITOR
  | group="main" sCount=1 dsCount=0 obj=0x415baca8 self=0x414f3580
  | sysTid=24899 nice=0 sched=0/0 cgrp=apps handle=1074295124
  | state=S schedstat=( 0 0 0 ) utm=32 stm=25 core=2
  at 应用包名.TestANRActivity.init(TestANRActivity.java:~0)
  - waiting to lock <0x41733870> (a 应用包名.TestANRActivity) held by tid=15 (Thread-203)
  at 应用包名.TestANRActivity.access$100(TestANRActivity.java:8)
  at 应用包名.TestANRActivity$1.onClick(TestANRActivity.java:25)
  at android.view.View.performClick(View.java:4445)
  at android.view.View$PerformClick.run(View.java:18429)
  at android.os.Handler.handleCallback(Handler.java:733)
  at android.os.Handler.dispatchMessage(Handler.java:95)
  at android.os.Looper.loop(Looper.java:136)
  at android.app.ActivityThread.main(ActivityThread.java:5001)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:515)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:736)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:570)
  at dalvik.system.NativeStart.main(Native Method)

traces.txt日志分析,可以看到
at 应用包名.TestANRActivity.init(TestANRActivity.java:~0)
waiting to lock <0x41733870> (a winbons.com.myapplication.TestANRActivity) held by tid=15 (Thread-203)

init等待锁,这个锁被tid=15 (Thread-203)持有了.

"Thread-203" prio=5 tid=15 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 obj=0x41a9da90 self=0x6ba96b58
  | sysTid=25026 nice=0 sched=0/0 cgrp=apps handle=1805145208
  | state=S schedstat=( 0 0 0 ) utm=0 stm=0 core=5
  at java.lang.VMThread.sleep(Native Method)
  at java.lang.Thread.sleep(Thread.java:1013)
  at java.lang.Thread.sleep(Thread.java:995)
  at android.os.SystemClock.sleep(SystemClock.java:115)
  at 应用包名.TestANRActivity.testANR(TestANRActivity.java:30)
  at 应用包名.TestANRActivity.access$000(TestANRActivity.java:8)
  at 应用包名.TestANRActivity$1$1.run(TestANRActivity.java:20)
  at java.lang.Thread.run(Thread.java:841)

可以看到tid=15 (Thread-203) 是一个子线程,正在 应用包名.TestANRActivity.testANR中执行SystemClock.sleep,导致的问题.

平时出现ANR问题,我们就可以通过traces.txt文件来分析具体的原因,定位以及解决问题

你可能感兴趣的:(Android性能优化1)