一个应用App的启动速度可以影响用户的首次体验,启动速度较慢(感官上)的应用可能致使用户再次开启App的意图降低,或者卸载放弃该应用程序。本文会经过如下几个方面来介绍应用启动的相关指标和优化,提供应用的启动速度。html
总体文章思路以下:python
一般来讲,启动方式分为两种:冷启动和热启动。android
二者之间的特色以下:程序员
冷热启动时间的计算命令:面试
adb shell am start -W [packageName]/[packageName.XxxActivity]
能够看到二者时间相差比较大。
根据该命令基本能够看出一个应用的启动速度了,从冷启动热启动的相关关系,当咱们须要优化启动速度的时候,优化冷启动速度便可。
可是该命令咱们只是大概知道应用的启动速度,但并不知道咱们的应用具体哪一个位置耗时,影响启动速度,后续我会介绍如何获取启动具体耗时时间。shell
常规获取时间方法无非就是在方法执行前记录下时间,在方法执行完毕后记录时间,二者时间之差就是该方法执行的时间,封装一个基础类以下:编程
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方法执行的时间微信
这样已经很直观了,能够具体到该方法的执行时间,若是要继续分析则对该方法内部继续执行该代码便可。可是这里有一个问题若是要知道10个或者更多方法的执行时间,这个方法看起来是能够,但写起来过于繁琐,且不符合程序员的习惯,关于这种场景后面会介绍如何处理。架构
@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打开改文件
1处能够看出有多少线程。
2处能够看出具体方法的耗时。
3处有两个选项:
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线程时间相对来讲减小不少。
在代码的开始位置加上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
操做相关应用,便可以抓取整个过程的相关信息:
便可以看到添加的tag“AppOnCreate”,对应的时间信息:
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; } }
引入以后结果以下:
能够看到具体方法的耗时。
采用注解方式,其中Around 须要有必定的AspectJ相关的语法
1.采用线程加载一些资源,好比sdk初始化,配置信息拉取等相关资源。线程,线程池,IntentServices都可以,配合延迟效果更好。
2.当咱们采用线程之间的可能会存在各线程之间相互等待依赖等相关问题,资源A线程必须在资源B加载完成,才能加载,但二者又会在不一样的线程之间,此时简单的办法能够采用CountDownLatch来实现。其总体思路以下图
3.使用 Pipeline 机制,根据业务优先级规定业务初始化时机,制定启动框架,它们为各个任务创建依赖关系,最终构成一个有向无环图。对于能够并发的任务,会经过线程池最大程度提高启动速度。不管是微信的mmkernel 仍是阿里的Alpha 都具有这种能力。
4.其余方案:
除了上述几种,咱们也能够利用IdealHandler,dex分包等相关方式作到启动优化。
上面主要介绍了如何获取启动的相关事件和相关优化知识点。关于时间就是尽可能使用工具,关于优化总体思路就是能预加载能延迟加载的资源尽可能去预加载去延迟加载,能异步的业务尽可能异步。
固然优化这个话题也是要根据具体的业务逻辑来定,总之:
对于启动优化要警戒 KPI 化,咱们要解决的不是一个数字,而是用户真正的体验问题。
上述只是提供一些思路和方式,还有不少奇淫技巧,欢迎给位大佬评论指出。
感谢你们能耐着性子看完啰里啰嗦的文章
在这里我也分享一份私货,本身收录整理的Android学习PDF+架构视频+面试文档+源码笔记,还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料帮助你们学习提高进阶,也节省你们在网上搜索资料的时间来学习,也能够分享给身边好友一块儿学习
若是你有须要的话,能够点赞+评论,关注我,而后加我VX:15388039515 我发给你
(或关注微信公众号“Android开发之家”回复【资料】免费领取)