性能优化(四)-启动优化1

1、启动图

image.png

因此,我们可以 整体的将应用启动分成三个阶段:

  • 第一阶段:点击桌面Launcher应用的图标,通过与AMS(ActivityManagerService)通信,启动应用的过程。这段时间,应用开发无能为力。

  • 第二阶段:应用Application执行过程。这个阶段Applicaton会执行attachBaseContext(),会执行onCreate回调。这个时候是黑白屏。我们再style的background可以放个图,给一种已经进入app的错觉。

  • 第三阶段:启动MainActivity执行过程。显示了应用的主要内容才算app启动完成。ActivityThread中有一个函数handleResumeActivity(),,这个函数调了onResume之后,有个wm.addView(decor,l)。也就是onResume()执行完之后,才会decorView显示到windows上。这个过程之后,就进入到了可见可交互状态,用户才会觉得app已经运行起来了。

void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason){
... 省略不需要的代码
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest,reason);// 这个里面会间接的调用activity的onResume 函数
...省略不需要的代码
if (a.mVisibleFromClient) {
    if (!a.mWindowAdded) {
        a.mWindowAdded = true;
        wm.addView(decor, l); // 代码1
    } else {
        a.onWindowAttributesChanged(l);
    }
}

...
}

2、优化方向

  • 1、第一阶段的优化。主要是launcher和AMS交换,及AMS启动应用的过程,framework做得,咱没法动

  • 2、第二阶段的优化。

    • part1 attachBaseContext回调方法的优化。apk加固 热修复 等dex操作都在这里处理,要分而治之。目前google对5.0及以后的多dex文件加载做了优化,暂时不用考虑。apk加固等天生需要时间。优化方向就是要降低耗时尽量别加固
    • part2 oncreate回调方法的优化。这个是核心。主要处理一些sdk、网络、数据库、SP等。根据业务需求,并不一定都要在这里处理,根据业务需要,将一些不需要立即加载的库放到异步线程中区处理。
      • 异步线程?那么jvm,线程切换的时间怎么管理
      • 使用线程池,每个sdk自己独立的线程池,如何处理?任务先后怎么处理》
      • 有些任务必须在UIThread中初始化怎么办?
      • 【用到的技术】拓扑排序图论 – 掘金 (juejin.cn)、线程管理【待补充】、优先级管理【待补充】等技术、
    • part3 应用执行到MainActivity之前的白屏处理
  • 3、第三阶段的优化

    • 第一个activity运行到OnResume函数执行完,才算执行完成。因此onCreate()\onStart()\onResume()都是需要优化的对象。
    • onCreate()优化
      • 1、布局优化,,简化布局用constraintLayout。
      • 2、异步加载试视图 AsyncLayoutInflate
      • 3、用composer,因为xml是反射加载的,速度比较慢一点。
      • 4、掌阅的X2C,在编译时,生成布局java代码,就不用反射了。
    • onStart/onPause
      • 1、用缓存下,如果异步加载成功,会更新缓存。
      • 2、初始化启动时,最好只用一个接口就拉去启动mainactivity和主activity所需数据。
      • 3、懒加载,比如viewpager懒加载。
      • 4、IdleHandler,把耗时任务丢到idleHandler里执行,提高速度。主线程没事做才会跑这个。
    • 总结就是
      • 合理使用异步初始化、延迟初始化、懒加载机制
      • 启动过程比卖你耗时操作,比如 数据库I/O操作不要放在主线程执行
      • 类加载优化:提前异步执行类加载
      • 合理使用IdleHandler进行延迟初始化
      • 简化布局

3、总结

  • App的启动耗时= app第一个activity 显示的时候(onWindowFocusChanged函数调用的时刻) — application 执行

  • 要优化的点。1、application的attachBaseContext(),onCreate().Activity 的onCreate onstart onResume

4、严苛模式

StrictModel是一个开发人员工具检测出我们可能无意做的事情,并提醒我们注意以便我们能够修复她们。

public class MyApplication extends Application {


@Override

public void onCreate() {

if (BuildConfig.DEBUG) {

//线程检测策略

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()

.detectDiskReads() //读、写操作

.detectDiskWrites()

.detectNetwork() // or .detectAll() for all detectable problems

.penaltyLog()

.build());

StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()

.detectLeakedSqlLiteObjects() //Sqlite对象泄露
.detectLeakedClosableObjects() //未关闭的Closable对象泄露

.penaltyLog() //违规打印日志

.penaltyDeath() //违规崩溃

.build());

}

}

5、启动黑白屏

当系统加载并启动 App 时,需要耗费相应的时间,这样会造成用户会感觉到当点击 App 图标时会有 “延迟” 现象。
为了解决这一问题,Google 的做法是在 App 创建的过程中,先展示一个空白页面,让用户体会到点击图标之后立
马就有响应

<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/bg</item>
</style>
<activity
android:name=".activity.SplashActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

然后在Activity的onCreate方法,把Activity设置回原来的主题

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

6、启动状态

  • 冷启动
    • 从头开始启动
  • 热启动
    • Activity仍驻在内存中,应用则不必重复执行对象初始化、布局加载和绘制
  • 温启动
    • 启动时间介于两者之间,
      • 用户退出应用后又重新启动应用,进程可能为被销毁,继续运行,但因公许哟啊执行onCreate()从头开始创建Activitiy
      • 系统将应用从内存中释放,然后重启。进程和Acitivtiy需要重启,但传递到onCreate()中已保存的实例state bundle对完成任务又一定帮助

7、启动耗时

  • 冷启动用了 5 秒或更长时间。
  • 温启动用了 2 秒或更长时间。
  • 热启动用了 1.5 秒或更长时间。

8、系统日志统计

在 Android 4.4(API 级别 19)及更高版本中,logcat 包含一个输出行,其中包含名为 Displayed 的值。此值代表从启动进程到在屏幕上完成对应 Activity 的绘制所用的时间。

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms

如果我们使用异步懒加载的方式,那么 Displayed日志已经打印,但是内容还在加载中。那么异步加载后可以调用activity.reportFullyDrawn()方法 来让系统打印到调用此方法位置的启动耗时。

9、adb命令统计

adb [-d|-e|-s <serialNumber>] shell am start -S -W
com.example.app/.MainActivity
-c android.intent.category.LAUNCHER
-a android.intent.action.MAIN

启动完成后,将输出:

  • ThisTime: 415
  • TotalTime: 415 咱们要关注的。
  • WaitTime: 437
    WaitTime:总的耗时,包括前一个应用Activity pause的时间和新应用启动的时间;

ThisTime表示一连串启动Activity的最后一个Activity的启动耗时;
TotalTime表示新应用启动的耗时,包括新进程的启动和Activity的启动,但不包括前一个应用Activity pause的耗时。

image.png

9、CPU profile java traceview

8.0以下

image.png

10、Debug API

除了直接使用 Profifile 启动之外,我们还可以借助Debug API生成trace文件。

public class MyApplication extends Application {

public MyApplication() {
Debug.startMethodTracing("enjoy");
}
//.....
}

public class MainActivity extends AppCompatActivity {
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Debug.stopMethodTracing();
}

//.......
}

运行App,则会在sdcard中生成一个enjoy.trace文件(需要sdcard读写权限)。将手机中的trace文件保存至电
脑,随后拖入Android Studio即可。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYlZ6fKf' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片