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>标签复用布局,include只支持android:layout_开头的属性
使用<merge>标签减少布局层级

<!-- 未使用merge -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    ...
</LinearLayout>
不使用merge
<!-- 使用mrge -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    ...
</merge>
使用merge

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

使用ViewStub

<ViewStub
        android:id="@+id/view_stub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/布局C" />

加载的两种方式:

((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文件来分析具体的原因,定位以及解决问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 前言 Android性能优化对Android程序的维护和拓展是有很大帮助的,我们知道Android手机不管是内存还...
    老实任阅读 504评论 0 0
  • 太长不看版:在 Android UI 布局过程中,遵守一些惯用、有效的布局原则,可以制作出高效且复用性高的 UI。...
    Mupceet阅读 3,807评论 0 14
  • 注意事项: 布局优化;尽量使用include、merge、ViewStub标签,尽量不存在冗余嵌套及过于复杂布局(...
    HarryXR阅读 5,147评论 1 19
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • 曾经,恐龙还是这个世界的霸主。它们喜爱光和热,因此努力长大,希望可以亲吻太阳。 它们的渴望愈加虔诚,于是翼龙出现...
    苍默阅读 115评论 0 0