Android性能优化(一)App启动时间的优化

本文探讨了Android应用的冷启动和热启动,详细解析了App启动流程,强调了启动时间计算的重要性。通过分析Application和Activity的创建过程,提出启动优化策略,包括主题替换、异步初始化第三方组件、延迟初始化和避免耗时操作。经过实践,启动速度提高了35.3%,展示了有效的优化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:App启动方式

1、冷启动:当启动应用时,后台没有该应用的进程,系统要重新创建一个新的进程分配给该应用,这种启动方式就是冷启动。冷启动首先会为应用创建一个新进程,然后创建并初始化Application和Activity,最后将界面显示出来

2、热启动:当启动应用时,后台已经存在该应用的进程(比如:按Home键、Back键的时候,应用虽然退出了前台,但后台依然保存着应用的进程),这种情况下,会直接从已有的进程中启动应用,这种叫做热启动。热启动会直接将应用从后台拉起,不走App进程、Application、Activity的创建和初始化这几步,而是直接将应用显示在前台

二:App启动流程

从App启动方式来看,冷启动最缓慢,App本身的工作要从头开始,下面是App冷启动的流程:

1.加载启动App

2.启动后立即显示出一个空白的Window,就是我们常见的白屏或黑屏

3.创建APP进程

4.创建App主线程

5.创建Application对象

6.创建Activity对象

7.View绘制,第一次显示屏幕

上面的步骤1~4是启动App固有的系统流程,不是我们能控制的,所以不在优化的考虑范围内,可优化的空间是Application及Activity的创建、初始化

Google给我们的启动加速方向是:

1.替换提前展示的空白Window界面,给用户一个快速打开APP的感觉

2.避免在启动时做密集沉重的初始化工作

3.定位问题:避免I/O操作、反序列化、网络操作、布局嵌套等

接下来就基于这个几方向去讲解一下App启动优化的方法

三:启动之主题替换

通常打开一个App的时候都是立即就展示出一个欢迎界面之类的,而不是白屏或者黑屏,其实这是对启动界面的主题进行了替换而已

在我们的styles文件中自定义一个样式Launcher,放置一张背景图,如下

    <style name="CustomActionBarTheme.Launcher">
        <item name="android:windowBackground">@drawable/splash_bg</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFullscreen">true</item>
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

在windowBackground中放置一个背景图,设置其他属性使图片全屏显示,然后将样式设置给启动Activity

        <activity android:name=".activity.SplashActivity"
            android:theme="@style/CustomActionBarTheme.Launcher"
            >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

这样启动时候就可以立即展示你所设置的背景图了,如果想要在启动Activity中显示回原来的主题,可以在Activity中这样设置

@Override
    protected void onCreate(Bundle savedInstanceState) {
        //替换为原来的主题,在onCreate之前调用
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
    }

四:启动时间计算

在cmd中输入adb shell am start -W [包名]/[全类名],即通过adb启动我们的Activity,控制台会输出启动时间

主要关注ThisTime、TotalTime和WaitTime三个数据,那么这三个时间分别代表什么呢?

  • ThisTime:所有被启动的Activity中最后那个Activity的启动耗时
  • TotalTime:所有Activity的启动耗时,包括创建进程+Application初始化+Activity初始化到界面显示,一般开发者只需要关心这个值,这才是应用的真正启动耗时;例子中一共就启动了一个Activity,所以ThisTime和TotalTime相等
  • WaitTime:就是总的耗时,包括前一个应用 Activity pause 的时间和新应用启动的时间

App启动时间的优化重点关注的是Application和第一个显示Activity,一般来说项目都会在Application的onCreate方法中做一些全局的初始化工作,所以下一步去看看我们的Application中做了什么

五:App启动的优化

这是一个Application中的初始化操作

        //EventBus初始化
        EventBus.getDefault().register(this);
        // 百度地图的初始化,在使用SDK各组间之前初始化context信息,传入ApplicationContext
        SDKInitializer.initialize(this);
        //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
        //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
        SDKInitializer.setCoordType(CoordType.BD09LL);
        //初始化友盟
        initUm();
        //初始化路由Arouter
        initRouter(this);
        //初始化日志收集
        initCrashReport();
        //初始化http
        initRxHttp();

现在我想统计上面这些方法的执行耗时,在代码之间插入Debug.startMethodTracing(filename)和Debug.stopMethodTracing()就可以追踪所包含代码的执行耗时,这些数据会写入一个.trace文件中,只要导出这个文件就可以看到详细信息了

                   
          
//代码追踪开始,参数是trace文件保存在手机的全路径名  
Debug.startMethodTracing(this.getExternalFilesDir(Environment.MEDIA_MOUNTED).getPath() + "01");
        //EventBus初始化
        EventBus.getDefault().register(this);
        // 百度地图的初始化,在使用SDK各组间之前初始化context信息,传入ApplicationContext
        SDKInitializer.initialize(this);
        //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
        //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
        SDKInitializer.setCoordType(CoordType.BD09LL);
        //初始化友盟
        initUm();
        //初始化路由ARouter
        initRouter(this);
        //初始化日志收集
        initCrashReport();
        //初始化http
        initRxHttp();
        //代码追踪结束
        Debug.stopMethodTracing();

执行以上代码,然后通过将在cmd中输入adb pull [trace文件保存在手机的全路径名] 导出trace文件到电脑中,再通过Android Studio打开文件

从图中可以看到代码中每个方法的执行时间和占用时间的百分比,initRouter时间占比55.6%、initUm占比20.1%、SDKInitializer.initialize占比19.5%,主要是这个三个初始化占用了大多数时间,它们分别是路由框架ARouter,友盟和百度地图的初始化

一些常用的优化思路:

  • 考虑异步初始化第三方组件,不阻塞主线程
  • 延迟第三方的初始化时间,因为异步初始化有可能遇到初始化还没完成主线程已经用到的情况,这种情况可以考虑延时到第三方组件使用之前进行初始化
  • 数据库、IO操作、网络请求尽量不要在Application中执行,能异步初始化的就尽量异步,如果不能异步初始化就尽量延时,不要在Application中创建线程池
  • 在首页Activity中,布局尽量减少嵌套,在onCreate、onStart、onResume方法中尽量避免耗时操作

因为首页activity要用到组件ARouter,所以我考虑把它的初始化延时到SplashActivity中的使用前,经测试,百度地图不能在子线程初始化,所以考虑延时,然后友盟初的始化放在子线程

    //在Application中创建工作线程进行相关初始化
    private void initOnWorkThread() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //将线程设置为后台,避免和主线程争抢资源
                Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
                initUm();
                initCrashReport();
            }
        }).start();
    }


        //将下面初始化延迟到首次显示Activity的onCreate方法中进行,界面完成以后才执行run方法
        //要让界面先显示出来,初始化完成以后再进行登录等其他操作
        findViewById(R.id.splash_view).post(new Runnable() {
            @Override
            public void run() {
                //初始化ARouter
                ARouter.init(ComApplication.getInstance());
                // 在使用 SDK 各组间之前初始化 context 信息,传入 ApplicationContext
                SDKInitializer.initialize(ComApplication.getInstance());
                //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
                //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
                SDKInitializer.setCoordType(CoordType.BD09LL);

                //登录等其他操作
                ........
            }
        });

来看一下优化以后的启动时间

六:优化前后对比

优化前时间 优化后时间 时间相差 提升百分比
1560       1009    551  35.3%

优化启动速度整整提升了35.3%,效果还是比较满意的,上面就是我对App启动时间优化的总结和实践

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值