Android App秒开,狭义的讲是指你的App的Activity从启动到显示所花费的时间在1秒之内,广义的讲是指这个过程所花费的时间越少越好。这个时间越短,你的App给用户的感受就是响应越快,使用越流畅,用户体验更好。秒开是Android App的一个很重要的性能指标。须要咱们持续的给予关注和优化。 #如何优化秒开 Google提供了不少性能优化的建议和官方的工具,网上也有很是多的关于Android App性能优化的文章和工具,能够帮助你解决大部分卡顿的问题。可是现实却多是即便你付出了不少精力去作优化,你的App仍是在启动新Activity的时候花费过多的时间。特别是随着需求的不断增加,你的App会变得复杂而庞大,要作优化首先要定位须要优化的点,而这会变得愈发困难。同时大型App在启动新Activity的时间花费过多状况出现的可能性反而会愈来愈大。html
在众多的优化建议中,有一条比较基本的原则是尽可能避免在主线程(或者说UI线程)中进行耗时操做。例如文件读写操做、网络请求、大量计算、循环等等。直观的理解是由于启动新Activity须要在主线程执行不少代码,例如onCreate()等生命周期的回调。若是此时有耗时操做的代码在主线程被执行,到新Activity展现出来所须要的时间就会延长。要优化秒开,首先要能监测主线程的运行状态,那么问题来了,主线程究竟是怎样在运行呢?你的代码又是何时,如何在主线程被执行的呢?java
要了解主线程的工做过程,首先要了解Android的消息机制。android
先看一下现实生活中的一个例子,虽然如今都是移动支付了,但相信你们都去银行取过钱。当你到达银行的时候,若是你是第一个,那恭喜你,你能够立刻到柜员那里办理你的业务;若是你前面还有人,那就比较惨了,你须要排队,得等到你前面的人都办完业务才会轮到你;更可怕的是若是你前面有几位须要办理的业务花费的时间比较长,那你须要等更长的时间;后面来的人则会按顺序排在你身后,和你同样不耐烦的琢磨何时才能轮到本身。git
抽象一下,消息机制其实和这个例子十分相似。每一个人都看作是个消息,何时到的银行是不肯定的。柜员能够看作一个消息处理器,他帮你办业务就至关于在处理你的消息;而人们按照前后顺序排起来的队伍能够看作是个消息队列。因此这个过程能够抽象为有个消息处理器,他有个消息队列,随机来到的消息按照必定顺序排列在这个队列里,消息处理器不停的从队列头部获取消息而后处理之,周而复始的循环重复这个过程。以下图所示: github
消息机制首先得有消息,在Android中就是Message。怎样能肯定一个消息呢?消息要有来源或者目标,也就是target;消息要代表本身要作什么,也就是what或者callback;消息要代表本身但愿在何时执行,也就是when。有了这几个要素,基本上这个消息就是个完备的消息了,能够被加入到消息队列中了。Android中的消息队列是MessageQueue。消息处理循环是Looper。Looper是个死循环,不停的从MessageQueue中获取消息而后处理之,具体的执行是在Handler里面进行的。另外消息加入消息队列也须要Handler来操做。Message,MessageQueue,Looper,Handler组合在一块儿,就构成了整个Android的消息机制。性能优化
Android的主线程就运行着这样一个消息机制。bash
主线程是在ActivityThread中建立的,能够看到在main函数中网络
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
}
复制代码
主线程实现了一个消息机制。因此Android的主线程就是个消息处理的循环。它所作的工做就是在不停的从消息队列获取消息,处理消息,周而复始。你的App全部的在UI上的操做,例如点击事件的处理、页面动画、显示更新页面、View绘制、启动新Activity等操做都是在给主线程发消息,主线程而后挨个处理这些消息。app
咱们了解了主线程的工做机制后,就要看看主线程中的消息处理是如何影响Activity秒开的。 当咱们要启动一个新的Activity的时候,从调用startActivity开始到新Activity显示出来,Android系统会发送一系列的消息给主线程。这一系列的消息处理所花费的总时间会影响页面的秒开,若是执行时间过长,用户就会有响应很是慢的感受。此外,除了Android系统会给主线程发消息,App自身也会给主线程发消息,若是在启动新Activity的过程当中,这些App本身的消息正好插入这一系列的Android系统消息中,那也会致使总的处理时间延长,形成不能秒开。 ide
了解了影响秒开的因素以后,咱们只要有办法能监测主线程中每一个消息处理时间,咱们就能定位到形成页面卡慢的缘由,而后再作优化。 幸亏Android工程师为咱们在Looper中预留了打log的位置。
public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
...
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
...
msg.recycleUnchecked();
}
}
public void setMessageLogging(@Nullable Printer printer) {
mLogging = printer;
}
复制代码
可见在消息被处理的开始和处理结束以后都会打印log。 你只须要在代码中调用Looper.setMessageLogging()设置一下就好。
Looper.getMainLooper().setMessageLogging(new Printer() {
@Override
public void println(String s) {
Log.v("debug", s);
}
});
复制代码
编译运行你的程序,你会在logcat输出看到相似这样的log:
在你启动一个新的Activity的时候你能够观测这样的log输出,看看里面有没有处理时间比较长的消息,或者看看里面有没有App本身的消息被处理,若是有的话,这些都是须要优化的点。
然而直接看log的缺点是这样的log会比较多,并且并不容易定位启动Activity的开始和结束时间点,另外每一个消息处理的时间也要本身计算,并非十分直观。
为了方便的进行秒开优化,我作了个工具叫StallBuster来协助定位Activity秒开失败的缘由。
集成StallBuster很是简单,只须要两步就能够了
dependencies {
compile 'com.github.zhangjianli:stallbuster:1.1'
}
复制代码
public class YourApplication extends Application {
@Override
public void onCreate() {
StallBuster.getInstance().init(this);
super.onCreate();
}
}
复制代码
这样就能够了,编译运行你的App。在你的App中打开新的Activity,StallBuster会发出一个Notification。告诉你刚启动这个Activity花了多少毫秒
对于每条记录,首先显示的是这条消息开始被处理的时间戳。而后是cost字段,表示处理这条消息花了多长时间。正常状况下是字体是黑色的;若是处理时间过长,则显示为红色。代表这里多是咱们须要优化的地方。
接下来是target字段,对应的是这个消息是被哪一个Handler处理的。Android系统的Handler会显示为黑色;App本身的Handler会显示为红色,代表这个消息不该该在启动Activity的时候出现,这里也多是须要优化的地方。
例如上图中第一条记录,.MainActivity$StallHandler处理这个消息花费了142ms。这会使启动SubActivity的时间至少延长了142ms。而这个Handler是App本身的Handler。咱们须要调试代码使得在启动这个Activity的时候确保不会有来自这个Handler的消息,142ms的时间就会节省下来。
最后一个字段是message或者callback。对应的是Message中的what或callback。有了这些信息咱们就能很方便的定位主线程中影响秒开的消息,进而优化咱们的App。
StallBuster就给你们介绍到这里,但愿StallBuster能帮到你。若是你们有任何建议或者问题请给我留言。
App秒开是是一项很是重要的性能指标。秒开的优化是个复杂的工做,有不少因素会影响App秒开。其中比较重要的一个因素是启动Activity的时候主线程的消息处理状况。在启动Activity过程当中须要避免消息处理时间过长,也要避免在此期间有App本身的消息须要处理。优化的关键点是要定位到主线程中的耗时操做,咱们能够经过打印分析主线程的消息处理log来定位,但这种方式并非很直观方便。这时可使用StallBuster帮助你快速定位秒开问题点,让秒开优化变的更加简单。