Android性能优化


目录

  • 1)布局优化
  • 2)绘制优化
  • 3)ListView和Bitmap优化
  • 4)线程优化
  • 5)App启动优化
  • 6)内存优化
  • 7)电量优化
  • 8)网络优化
  • 9)性能优化工具
  • 10)响应速度优化和ANR日志分析
  • 11)一些性能优化建议

1)布局优化

布局优化就是尽量减少布局文件的层数。

方式 说明
去掉其他不必要的背景 overdraw (过渡绘制)的关键点在于一个像素被绘制了几次
<include> 可以将一个指定的布局文件加载到当前布局文件中
<merge> 一般和<include>一起使用,可以少一层嵌套
ViewStub 继承View,更轻量级且宽高为0。可以做到按需加载以提升性能,而不是界面初始化的时候加载,如网络异常的界面。
<include layout="@layout/merge_button">
// ~res/layout/merge_button.xml
<merge xmlns:android="http://schemas.android.com/apk/res/android">
  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />
</merge>
<ViewStub
  android:id="@+id/stub_import"
  android:layout="layout/xxx"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
/>
//通过setVisibility后,ViewStub就会被他内部的布局替换掉
(ViewStub)findViewById(R.id.stub_import).setVisibility(View.VISIBLE)
工具 说明
Layout Inspector Tools -> Android -> Layout Inspector
调试GPU过度绘制功能 手机-开发者选项

2)绘制优化

Android 屏幕刷新机制
android屏幕刷新显示机制
Google的官方性能标准,View的绘制帧率保持在60fps为最佳,这就要求每一帧的绘制时间不超过16ms(1000/60)。

正常绘制

丢帧,卡顿

View的onDraw()要避免大量操作

  • 因为onDraw()会被频繁调用,所以此方法内不要创建局部变量。大量局部变量会造成频繁GC,频繁GC也会造成卡顿,因为GC会中断程序运行。
  • onDraw()不要做耗时任务

3)ListView和Bitmap优化

请参阅之前笔记。

  • ListView 避免在getView()中执行耗时操作,其次快速滑动时无需开启大量异步任务去请求图片。
  • Bitmap 图片压缩和缓存

4)线程优化

  • 采用线程池,避免大量的Thread。

5)App启动优化

5.1) 在Application初始化的时候执行了大量的操作

  • 通过traceview检查方法执行时长
  • 采用IntentService在线程中加载操作
//~ MainApplication.java
    public void onCreate()
    {
        Debug.startMethodTracing("Application");

        super.onCreate();

        //ARouter init
        if (BuildConfig.DEBUG) {           // 这两行必须写在init之前,否则这些配置在init过程中将无效
            ARouter.openLog();     // 打印日志
            ARouter.openDebug();   // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
        }
        ARouter.init(this); 
        //jpush init
        JPushInterface.init(this);
        //shareSDK init
        ShareSDK.initSDK(this); 
        //RNinit
        SoLoader.init(this, /* native exopackage */ false);

        //LeakCanary
        if (LeakCanary.isInAnalyzerProcess(this)) {
            // This process is dedicated to LeakCanary for heap analysis.
            // You should not init your app in this process.
            return;
        }
        LeakCanary.install(this);

        Debug.stopMethodTracing();
    }
运行后可以在sdcard中找到trace

打开 也可以Monitor打开

5.2)首屏加载不要耗时过长

App没有完全起来时, 屏幕会一直显示一块空白的窗口。
Android最新的Material Design建议我们使用一个placeholder UI来展示给用户直至App加载完毕

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 底层白色 -->
    <item android:drawable="@android:color/white" />

    <!-- 顶层Logo居中 -->
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/ic_launcher" />
    </item>
</layer-list>

<style name="SplashTheme" parent="AppTheme">
    <item name="android:windowBackground">@drawable/logo_splash</item>
</style>
//启动页
public class SplashActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startActivity(new Intent(this,WelcomeActivity.class));
        finish();
    }
}
        <activity android:name=".ui.SplashActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/SplashTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


6)内存优化

内存抖动:短时间大量的对象被创建又释放,会造成锯齿状内存,产生频繁的GC,造成卡顿。
解决:1-避免循环创建对象;2-onDraw不要创建对象;3-对于无法避免可使用对象池。

一个永远不会被使用的对象,因为一些引用没有断开,没有满足GC条件,导致不会被回收

  • 静态变量(如一个静态变量持有了Activity的引用,将会导致Activity无法销毁)
  • 非静态内部类(非静态内部类如Handler或Runnable会维持一个到外部类实例的引用,可以使用静态内部类和WeakReference代替)
  • Handler临时性内存泄露(非静态的Handler持有外部如Activity引用,而MQ又持有Handler的引用)
  • 资源未关闭( Cursor、SQLiteDatabase,io流)
  • 广播和监听器没有反注册(unregister,removelistener)
  • adapter未使用contentView缓存

7)电量优化

adb bugreport > bugreport.txt

使用 Battery Historian.来导入bugreport通过图形界面查看电量消耗。

  • 优化网络请求
  • 监听手机充电状态(如手机充电时进行一些文件上传,用户数据同步等操作)
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                     status == BatteryManager.BATTERY_STATUS_FULL;
  • 6.0 Doze模式会延迟后台网络或cpu来减少电量消耗

8)网络优化

  • Android Porfiler监控网络请求
  • 更好的接口设计,更合理的接口调用。还可以打包网络请求
  • request Cache-Control
  • 弱网测试
  • 图片size

9)性能优化工具

性能优化工具
  • StrictMode -严格模式
        // 分别为MainThread和VM设置Strict Mode
        if (BuildConfig.DEBUG) {
            //线程策略
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectAll() //侦测一切潜在违规
                    .detectDiskReads() //侦测磁盘读
                    .detectDiskWrites() //侦测磁盘写
                    .detectNetwork()    //侦测网络操作
                    .detectCustomSlowCalls() //侦测自定义的耗时操作
                    .penaltyDialog() //违规时,向开发者显示一个恼人的Dialog对话框
                    .build());

            //虚拟机策略
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectLeakedSqlLiteObjects()
                    .detectLeakedClosableObjects() //当显式中止方法调用之后,假如可被Closeable类或其他的对象没有被关闭。
                    .detectLeakedRegistrationObjects()
                    .detectActivityLeaks()
                    .penaltyLog() //违规时,将违规信息写入系统日志
                    .build());
        }

  • Lint检查
    Analyze->Inspect Code


    Lint检查

  • HierarchyViewer的替代Layout Inspector
    Tools -> Android -> Layout Inspector


    Layout Inspector

  • TraceViewer

  • Android Porfiler


    Android Porfiler

  • 调试GPU过度绘制功能 手机-开发者选项



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

组件 ANR时间
Activity 5秒
BroadcastReceiver 10秒
Service 20秒

adb pull /data/anr/traces.txt 文件可以看到ANR日志


11)一些性能优化建议

  • 避免创建过多对象
  • 避免过多使用枚举,枚举占用内存空间大
  • 常量使用static final修饰
  • 使用Android特有数据结构,如SpaceArray何Pair等
  • 适当使用软引用和弱引用
  • 内存缓存和磁盘缓存
  • 尽量采用静态内部类,避免由于内部类导致的内存泄漏

参考资料

Android应用优化最全指南和清单
Android App优化之性能分析工具
Android APP 性能优化的一些思考

---`

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

推荐阅读更多精彩内容