Android性能优化--启动优化

1. 前言

一个应用App的启动速度可以影响用户的首次体验,启动速度较慢(感官上)的应用可能致使用户再次开启App的意图降低,或者卸载放弃该应用程序。本文会经过如下几个方面来介绍应用启动的相关指标和优化,提供应用的启动速度。html

总体文章思路以下:python

启动优化

2. 冷启动&热启动

一般来讲,启动方式分为两种:冷启动和热启动。android

  1. 冷启动:当启动应用时,后台没有该应用的进程,这时系统会从新建立一个新的进程分配给该应用,这个启动方式就是冷启动。
  2. 热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,可是该应用的进程是依然会保留在后台,可进入任务列表查看),因此在已有进程的状况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。

二者之间的特色以下:程序员

  • 冷启动:系统会从新建立一个新的进程分配给该应用,从Application建立到UI绘制等相关流程都会执行一次。
  • 热启动:应用还在后台,所以该启动方式不会重建Application,只会从新绘制UI等相关流程。

冷热启动时间的计算命令:面试

adb shell am start -W [packageName]/[packageName.XxxActivity]
  • 参数说明:
    一、ThisTime:通常和TotalTime时间同样。除非在应用启动时开了一个透明的Activity预先处理一些事再显示出主Activity,这样将比TotalTime小。
    二、TotalTime:应用的启动时间。包含建立进程+Application初始化+Activity初始化到界面显示。
    三、WaitTime:通常比TotalTime大点,包含系统影响的耗时。
    对于咱们的应用来讲结果以下:
  • 冷启动

冷启动

  • 热启动

热启动

能够看到二者时间相差比较大。
根据该命令基本能够看出一个应用的启动速度了,从冷启动热启动的相关关系,当咱们须要优化启动速度的时候,优化冷启动速度便可。
可是该命令咱们只是大概知道应用的启动速度,但并不知道咱们的应用具体哪一个位置耗时,影响启动速度,后续我会介绍如何获取启动具体耗时时间。shell

3. 常规获取时间方法

常规获取时间方法无非就是在方法执行前记录下时间,在方法执行完毕后记录时间,二者时间之差就是该方法执行的时间,封装一个基础类以下:编程

public class LaunchTimer {

 private static final String TAG = "LaunchTimer";
 private static long sTime;

 public static void startRecord() {
 sTime = System.currentTimeMillis();
 }

 public static void endRecord() {
 long cost = System.currentTimeMillis() - sTime;
 NLog.i(TAG, "执行耗时:%s", cost);
 }

}

使用方式以下,能够直观的看出createController方法执行的时间微信

createController耗时

这样已经很直观了,能够具体到该方法的执行时间,若是要继续分析则对该方法内部继续执行该代码便可。可是这里有一个问题若是要知道10个或者更多方法的执行时间,这个方法看起来是能够,但写起来过于繁琐,且不符合程序员的习惯,关于这种场景后面会介绍如何处理。架构

4. TraceView和SysTrace工具使用

  • TraceView使用:TraceView是Android平台配备一个很好的性能分析工具,它能够经过图形化的方式让咱们了解咱们要跟踪的程序的性能,而且能具体到方法。
    使用方式:
  1. 经过Android studio自带的traceview查看(Android profiler)。
  2. 经过Android SDK自带的Debug。
  3. 经过DDMS中的traceview查看。
    本文主要介绍第二种方式,经过sdk中的方法,对应用进行打点获取相关信息:
@Override
 public void onCreate(final Bundle icicle) {
 setTheme(R.style.BrowserTheme);
 Intent intent = getIntent();
 NLog.i(LOGTAG,"onCreate");
 super.onCreate(icicle);
 //开始记录,且该方法能够设置文件大小和路径
 Debug.startMethodTracing("browser.trace");
 Controller controller=createController();
 mController = controller;
 getWindow().getDecorView().setSystemUiVisibility(
 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
 controller.handleThirdPartyIntent(intent);
 //结束记录
 Debug.stopMethodTracing();
 }

如上能够在目录下能够生成以下文件并发

/sdcard/Android/data/com.xxx.xx.browser/files/browser.trace

导出改文件,经过Android Studio的profile打开改文件

traceview

1处能够看出有多少线程。
2处能够看出具体方法的耗时。
3处有两个选项:

  • wall clock time:代码在线程上执行的真正时间[有一部分是等待cpu轮询时间]
  • thread time :cpu执行的时间
    通常是优化的是cpu执行时间
    结合业务代码走查发现Controller0线程为一个线程,所以主线程一些操做能够放进去执行,从而减小main线程的耗时。走查代码能够发如今Controller0线程中执行以下
requestPermission();
 ExecutorService service = Executors.newSingleThreadExecutor(new NamedThreadFactory("Controller"));
 Future<Boolean> future = service.submit(new Callable<Boolean>() {
 @Override
 public Boolean call() throws Exception {
 try {
 asyncInit();

 } catch (Exception e) {
 return false;
 }
 return true;
 }
 });

requestPermission()方法执行在main线程中,所以咱们能够把其放在Controller0线程中执行,从而减小main线程的的时间

ExecutorService service = Executors.newSingleThreadExecutor(new NamedThreadFactory("Controller"));
 Future<Boolean> future = service.submit(new Callable<Boolean>() {
 @Override
 public Boolean call() throws Exception {
 try {
 requestPermission();
 asyncInit();

 } catch (Exception e) {
 return false;
 }
 return true;
 }
 });

经测试发现无问题,且对比此时的trace文件发现修改先后main线程时间相对来讲减小不少。

  • SysTrace使用:
    SysTrace用于收集可帮助您检查原生系统进程的详细系统级数据,例如CPU调度、磁盘活动、应用线程等,并解决掉帧引发的界面卡顿。
    使用方式:

在代码的开始位置加上tag

TraceCompat.beginSection("AppOnCreate");

而后指定位置结束

TraceCompat.endSection();

便可以抓取到整个应用在此过程的相关信息,例如在onCreate方法中添加上述两行代码,执行相关python命令:

python systrace.py -b 32768 -t 10 -a com.xxx.xxx.browser -o browser.html sched gfx view wm am app

操做相关应用,便可以抓取整个过程的相关信息:

systrace

便可以看到添加的tag“AppOnCreate”,对应的时间信息:

  1. Wall Duration 表明的方法从开始到结束的耗时
  2. CPU Duration 表明CPU的执行时间
    经过这两个参数能够看出此流程中执行的时间等相关信息
    咱们都知道CPU是轮询模式,所以优化的方向能够说是两个方向,提升CPU的核数和优化CPU执行的时间。

5. 经过AOP获取时间

  • AOP:面向切面编程(Aspect-Oriented Programming)。若是说,OOP若是是把问题划分到单个模块的话,那么AOP就是把涉及到众多模块的某一类问题进行统一管理。打个比方Android 里面PMS,AMS都拥有各自的职责,可是他们都须要经过log系统管理log,这就是一种AOP思想。

AspectJ其实是对AOP编程思想的一个实践,固然,除了AspectJ之外,还有不少其它的AOP实现,例如ASMDex,但目前最好、最方便的,依然是AspectJ。
AspectJ的使用以下:
根目录gradle下引用:

classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'

app目录gradle文件下引用:

implementation 'org.aspectj:aspectjrt:1.8.+'

此两处引用完成以后,就是代码编写:

package com.xx.xxx.browser.aspect;

import android.util.Log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class IntercepLifeCycleAOP {
 //获取该Activity下的全部on开头的方法耗时
 @Around("execution(* com.xxx.xxx.BrowserActivity.on**(..))")
 public Object getTime(ProceedingJoinPoint joinPoint) {
 Object proceed = null;
 long start = System.currentTimeMillis();
 try {
 proceed = joinPoint.proceed();
 } catch (Throwable throwable) {
 throwable.printStackTrace();
 }
 long end = System.currentTimeMillis();
 Log.d("IntercepLifeCycleAOP", joinPoint.getSignature().getName() + ":执行时间:" + (end - start));
 return proceed;

 }

}

引入以后结果以下:

AspectJ

能够看到具体方法的耗时。
采用注解方式,其中Around 须要有必定的AspectJ相关的语法

6. 用户体验优化

  1. 主题优化:经过给应用设置一个透明主题,在应用启动完成以后,再给其赋予本该有的主题,经过对启动页的主题设置后,就会将白屏/黑屏抹去,用户点击App的图标就展现启动图,让用户先产生启动很快的“错觉”。
  2. 动画兼容:根据不一样年代的机型能够选择执行或不执行相关动画,或者延迟其余相关操做,可根据device-year-class来判断具体年份
  3. UI布局优化。

7. 异步加载

1.采用线程加载一些资源,好比sdk初始化,配置信息拉取等相关资源。线程,线程池,IntentServices都可以,配合延迟效果更好。

2.当咱们采用线程之间的可能会存在各线程之间相互等待依赖等相关问题,资源A线程必须在资源B加载完成,才能加载,但二者又会在不一样的线程之间,此时简单的办法能够采用CountDownLatch来实现。其总体思路以下图

CountDownLatch

3.使用 Pipeline 机制,根据业务优先级规定业务初始化时机,制定启动框架,它们为各个任务创建依赖关系,最终构成一个有向无环图。对于能够并发的任务,会经过线程池最大程度提高启动速度。不管是微信的mmkernel 仍是阿里的Alpha 都具有这种能力。

4.其余方案:
除了上述几种,咱们也能够利用IdealHandler,dex分包等相关方式作到启动优化。

8. 总结

上面主要介绍了如何获取启动的相关事件和相关优化知识点。关于时间就是尽可能使用工具,关于优化总体思路就是能预加载能延迟加载的资源尽可能去预加载去延迟加载,能异步的业务尽可能异步。
固然优化这个话题也是要根据具体的业务逻辑来定,总之:

对于启动优化要警戒 KPI 化,咱们要解决的不是一个数字,而是用户真正的体验问题。

上述只是提供一些思路和方式,还有不少奇淫技巧,欢迎给位大佬评论指出。

Android学习PDF+架构视频+面试文档+源码笔记


感谢你们能耐着性子看完啰里啰嗦的文章

在这里我也分享一份私货,本身收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料帮助你们学习提高进阶,也节省你们在网上搜索资料的时间来学习,也能够分享给身边好友一块儿学习

若是你有须要的话,能够点赞+评论关注我,而后加我VX:15388039515 我发给你
(或关注微信公众号“Android开发之家”回复【资料】免费领取)

相关文章
相关标签/搜索