APP启动优化

   APP启动流程

       当用户在launcher上点击应用图标,系统需为app创建进程,app在进程中创建组件(即用户点击图标到显示第一个页面的过程)

    启动时间

    当Activity执行到onResume方法,再等待到View树构建完成,此时才算app完全启动

    在log日志中  查看叫  Displayed   日志  过滤一定要是  NoFilters

    命令行查看(需要Android4.4以后手机)

    使用adb shell am start -w <包名>可以统计应用启动时间,可以得到以下一些参数

    ThisTime:最后一个启动的Activity的启动耗时

    TotalTime:自己的所有Activity的启动耗时

    WaitTime:ctivityManagerService启动App的Activity时的总时间(包括当前Activity的onPause()和自己Activity的启动)

        

计算启动时间——Screen Record

    通过 adb shell screenrecord -bugreport /sdcard/test.mp4录制屏幕

   开始后,屏幕左上方   出现例如15:31:22.261 f=171(0) 15:31:22。261 表示当前时间,171表示第几帧,0表示掉帧率


启动优化方案

系统创建进程部分与rom相关,这部分无法优化,能够优化部分是应用部分

Application

作为程序主入口,很多开发人员喜欢在此处做一些初始化动作。特别是一些第三方SDK需在onCreate方法进行初始化,

当库比较多时,必然带来Application的负荷。

针对这种情况,可以通过以下方式解决

        1.延迟初始化
        2.开启后台任务
        3.进行界面预加载
具体分析耗时

  1.可以通过一些工具,如traceView分析耗时的方法和组件

  2.按功能和需求,对每个加载库,选择合适的启动时机


例如

1、在Application的构造器方法、attachBaseContext()、onCreate()方法中不要进行耗时操作的初始化,一些数据预取放在异步线程中,可以采取Callable实现。 
2、对于sp的初始化,因为sp的特性在初始化时候会对数据全部读出来存在内存中,所以这个初始化放在主线程中不合适,反而会延迟应用的启动速度,对于这个还是需要放在异步线程中处理。 

3、对于MainActivity,由于在获取到第一帧前,需要对contentView进行测量布局绘制操作,尽量减少布局的层次,考虑StubView的延迟加载策略,当然在onCreate、onStart、onResume方法中避免做耗时操作。



Theme

当系统加载一个activity,针对耗时操作,系统会先读取当前activity的主题,然后根据theme的主题绘制,当activity加载完成,

才替换为真正的界面

所以,Google官方提供的解决方案,就是通过android:windowBackground属性,来进行加载前的配置,同时,这里不仅可以配置颜色,还能配置图片,例如,我们可以使用一个layer-list来作为android:windowBackground要显示的图:

layer-list xmlns:android="http://schemas.android.com/apk/res/android"
            android:opacity="opaque">
    <item android:drawable="@android:color/darker_gray"/>
    <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/ic_launcher"/>
    </item>
</layer-list>

可以看见,这里通过layer-list来实现图片的叠加,让开发者可以自由组合。

接下来可以设置一个新的Style,这个Style就是Activity预加载的Style。

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="StartStyle" parent="AppTheme">
        <item name="android:windowBackground">@drawable/start_window</item>
    </style>
</resources>

OK,下面在Mainifest中给Activity指定需要预加载的Style:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.xys.startperformancedemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:theme="@style/StartStyle">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

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

</manifest>

这里需要注意下,一定是Activity的Theme,而不是Application的Theme。

最后,我们在Activity加载真正的界面之前,将Theme设置回正常的Theme就好了:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
        SystemClock.sleep(2000);
        setContentView(R.layout.activity_main);
    }
}

异步初始化

这个很简单,就是让App在onCreate里面尽可能的少做事情,而利用手机的多核特性,尽可能的利用多线程,例如一些第三方框架的初始化,如果能放线程,就尽量的放入线程中,最简单的,你可以直接new Thread(),当然,你也可以通过公共的线程池来进行异步的初始化工作,这个是最能够压缩启动时间的方式

延迟初始化

延迟初始化并不是减少了启动时间,而是让耗时操作让位、让资源给UI绘制,将耗时的操作延迟到UI加载完毕后,所以,这里建议通过mDecoView.post方法,来进行延迟加载,代码如下:

getWindow().getDecorView().post(new Runnable() {

  @Override public void run() {
    ……
  }
});

我们的ContentView就是通过mDecoView.addView加入到根布局的,所以,通过这种方式,可以让延迟加载的内容,在ContentView初始化完毕后,再进行执行,保证了UI绘制的流畅性。

IntentService

IntentService是继承于Service并处理异步请求的一个类,在IntentService的内部,有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要去手动控制。

public class InitIntentService extends IntentService {

    private static final String ACTION = "com.xys.startperformancedemo.action";

    public InitIntentService() {
        super("InitIntentService");
    }

    public static void start(Context context) {
        Intent intent = new Intent(context, InitIntentService.class);
        intent.setAction(ACTION);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        SystemClock.sleep(2000);
        Log.d(TAG, "onHandleIntent: ");
    }
}

我们将耗时任务丢到IntentService中去处理,系统会自动开启线程去处理,同时,在任务结束后,还能自己结束Service,多么的人性化!OK,只需要在Application或者Activity的onCreate中去启动这个IntentService即可:

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

使用ActivityLifecycleCallbacks

Framework提供的这个方法可以监控到所有Activity的生命周期,在这里,我们就可以通过onActivityCreated这样一个回调,来将一些UI相关的初始化操作放到这里,同时,通过unregisterActivityLifecycleCallbacks来避免重复的初始化。同时,这里onActivityCreated回调的参数Bundle,可以用来区别是否是被系统所回收的Activity。


其他方案

下面是两种不同的方案,都是在Style中进行配置:

<item name="android:windowDisablePreview">true</item>

<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>




    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值