android 启动优化方案,Android性能优化之启动优化

Android性能优化之启动优化

android 性能优化

App启动流程

首先要了解App的启动流程,详情参考面试之Android进阶

第一个Activity的优化

启动时间的量化

对于Activity来说,启动时,首先执行的是onCreate()、onStart()、onResume()这些生命周期函数,但即使这些生命周期方法回调结束了,应用也不算已经完全启动,还需要等View树全部构建完毕,一般认为,setContentView中的View全部显示结束了,APP也就完全启动了。

Display Time

从API19之后,Android在系统Log中增加了Display的Log信息,通过过滤ActivityManager以及Display这两个关键字,可以找到系统中的这个Log:

$adb logcat|grep“ActivityManager”

ActivityManager:Displayedcom.example.launcher/.LauncherActivity:+999ms

那么这个时间,实际上是Activity启动,到Layout全部显示的过程,但是要注意,这里并不包括数据的加载,因为很多App在加载时会使用懒加载模式,即数据拉取后,再刷新默认的UI。

reportFullyDrawn

系统日志中的Display Time只是布局的显示时间,并不包括一些数据的懒加载等消耗的时间,所以,系统给我们定义了一个类似的『自定义上报时间』——reportFullyDrawn。

eportFullyDrawn是由我们自己调用的,一般在数据全部加载完毕后,手动调用,这样就会在Log中增加一条日志:

$ adb logcat|grep“ActivityManager”

ActivityManager:Displayedcom.example.launcher/.LauncherActivity:+999ms

ActivityManager:Fullydrawn com.example.launcher/.LauncherActivity:+1s999ms

一般来说使用场景如下:

publicclassMainActivityextendsAppCompatActivityimplementsLoaderManager.LoaderCallbacks{

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

@Override

publicvoidonLoadFinished(Loaderloader,Voiddata){

// 加载数据

// ……

// 上报reportFullyDrawn

reportFullyDrawn();

}

@Override

publicLoaderonCreateLoader(intid,Bundleargs){

returnnull;

}

@Override

publicvoidonLoaderReset(Loaderloader){

}

}

计算启动时间——ADB

通过ADB命令可以统计应用的启动时间,指令如下所示:

➜~adb shell am start-W com.xys.preferencetest/.MainActivity

Starting:Intent{act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER]cmp=com.xys.preferencetest/.MainActivity}

Status:ok

Activity:com.xys.preferencetest/.MainActivity

ThisTime:1047

TotalTime:1047

WaitTime:1059

Complete

该指令一共给出了三个时间:

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

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

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

这三个时间不是很好理解,我们可以把整个过程分解

(注意以下5个事项)

1.上一个Activity的onPause()

2.系统调用AMS耗时

3.第一个Activity(也许是闪屏页)启动耗时

4.第一个Activity的onPause()耗时

5.第二个Activity启动耗时ThisTime表示5(最后一个Activity的启动耗时)。

TotalTime表示3.4.5总共的耗时(如果启动时只有一个Activity,那么ThisTime与TotalTime应该是一样的)。

WaitTime则表示所有的操作耗时,即1.2.3.4.5所有的耗时。

计算启动时间——Screen Record

通过录屏进行启动的分析,是一个很好的办法,在API21+,Android给我们提供了一个更加方便、准确的方式:

adb shell screenrecord--bugreport/sdcard/test.mp4

Android在screenrecord中新增了一个参数——bugreport,那么加了这个参数之后,录制出来的视频,在左上角就会增加一行数字的显示,如图所示。

在视频开始前,会显示设备信息和一些参数:

Application

优化的方法,无非是通过以下几个方面:延迟初始化

后台任务

界面预加载

App启动优化的一般过程:

1.通过TraceView、Systrace来分析耗时的方法与组件。

2.梳理启动加载的每一个库、组件。

3.将梳理出来的库,按功能和需求进行划分,设计该库的启动时机,安排启动顺序。

4.与交互沟通,设计启动画面,按前文方法进行优化。

延迟初始化

延迟初始化并不是减少了启动时间,而是让耗时操作让位、让资源给UI绘制,将耗时的操作延迟到UI加载完毕后。

方案一

getWindow().getDecorView().post(newRunnable(){

@Override

publicvoidrun(){

……

}

});

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

方案二

Looper.myQueue().addIdleHandler(newMessageQueue.IdleHandler{

@Override

publicbooleanqueueIdle(){

...

returnfalse;

}

});

queueIdle()的返回值:返回值为true,则保持此Idle一直在Handler中

否则,执行一次后就从Handler线程中remove掉。

冷启动、热启动冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用。

热启动:当启动应用时,后台存在该应用的进程(back键,home键,应用退出,但是没有销毁),从已有的进程中启动。

因为热启动是后台进程已经存在了,所以启动速度比较快,这里提到的优化是指冷启动。

白屏或者黑屏

为什么启动时会出现短暂黑屏或白屏的现象?当用户点击你的app那一刻到系统调用Activity.onCreate()之间的这个时间段内,WindowManager会先加载app主题样式中的windowBackground做为app的预览元素,然后再真正去加载activity的layout布局。

很显然,如果你的application或activity启动的过程太慢,导致系统的BackgroundWindow没有及时被替换,就会出现启动时白屏或黑屏的情况(取决于你的主题是Dark还是Light)。

解决方案一

甩锅给系统

@color/colorPrimary

@color/colorPrimaryDark

@color/colorAccent

true

主要是windowIsTranslucent,会替换白屏或者黑屏为透明色

用户点击icon,然后会会有段时间没有任何反应,这样用户误以为是手机慢了。

解决方案二

我们在style中自定义一个样式Lancher,在其中放一张背景图片,最好是跟我们启动页相关的色值

@drawable/bg

把这个样式设置给启动的Activity

android:name=".activity.SplashActivity"

android:screenOrientation="portrait"

android:theme="@style/AppTheme.Launcher"

>

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

@Override

protectedvoidonCreate(BundlesavedInstanceState){

//替换为原来的主题,在onCreate之前调用

setTheme(R.style.AppTheme);

super.onCreate(savedInstanceState);

}

这样在启动时就通过给用户看一张图片,而不是之前的黑屏和白屏了。

MultiDex

问题

安装完成并初次启动APP的时候,5.0以下某些低端机会出现ANR或者长时间卡顿不进入引导页,而罪魁祸首是MultiDex.install(Context context)的dexopt过程耗时过长。因此需要在初次启动时做特别处理。

解决这个问题的思路以及详细解释,大致分为3步:在Application.attachBaseContext(Context base)中,判断是否初次启动,以及系统版本是否小于5.0,如果是,跳到2;否则,直接执行MultiDex.install(Context context)。

开启一个新进程,在这个进程中执行MultiDex.install(Context context)。执行完毕,唤醒主进程,自身结束。主进程在开启新进程后,自身是挂起的,直到被唤醒。

唤醒的主进程继续执行初始化操作。

方案中有一个小难点是:主进程如何得知加载进程完成加载?

答案是Messenger

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值