Android性能优化之Splash页

来源:互联网 发布:php调用接口的方法 编辑:程序博客网 时间:2024/05/17 09:04

原文地址:http://blog.csdn.net/u010687392/article/details/50525697

目前SplashActivity的设计

目前市场上的应用在启动时基本上都会先启动一个SplashActivity,作为一个欢迎界面,为什么这样设计呢? 
个人总结有三个优点:

1、可以给用户更好的体验

比如:可以由后台动态的改变欢迎的图片,或者显欢迎xxx回来,新浪微博的就是这种交互。

2、可以缩减App的启动时间

由上一篇博文中知道app启动的耗时主要是在Application初始化中和MainActivity的界面绘制前,由于MainActivity的业务和布局复杂度肯定比只显示一张图片的界面高,所以,加入一个显示一张图片的Splash页可以优化应用的启动。

3、可以在应用启动时做更多的事

一般来说SplashActivity一般会设计成停留2到4s不等,或者根据数据的加载程度来动态的设置Splash界面的停留时间,既然停留那么久,那么当然可以在这个界面背后做一些事以备MainActivity的快速显示,比如:数据的预加载、sp的初始化、网络请求等。

当然你可能有些疑问,那这样初始化放在Application中也可以啊?也用异步操作数据也是一样啊?

答案是不一样!正如上篇所说的,Application初始化时并不会加载界面,而是在它创建完和初始化完成后,开始创建Activity时才开始绘制Theme中的background和绘制布局,所以用一个轻量的Splash页给它设置一张背景欢迎图,这样就立马能显示界面了,而在这个界面中还可以做其它的初始化操作,这样在视觉上即达到了app的快速启动,又添加了体验和做数据的初始化。

相反如果过多的放在Application中,则在点击app图标启动时会感觉延迟,必须要把Application中的东西都做完才进入Activity的配置和绘制中。

目前大多数应用的Splash页设计的不足之处

目前大多应用的Splash页设计都是利用一个Activity,取名叫SplashActivity,然后在这个SplashActivity中加入一个背景图,然后再new Handler().postDelayed()几秒中,再startActivity跳入主界面,这样设计看起来非常不错,既可以在SplashActivity初始化、预加载数据,还可以提高应用的启动速度。

不过这确实提高了应用的启动速度,毕竟我们比较快的看到了第一帧——SplashActivity,不过在SplashActivity之后,还需要调到MainActivity啊,虽然MainActivity中的一些数据可以在SplashActivity做预取,不过这中间需要有Intent的传递过程,而且MainActivity中布局还没加载进来,所以还是需要再加载和绘制布局界面,然后才能填入数据,所以这样看来,在跳转到MainActivity中,还是需要做界面的绘制和数据的加载(包括Intent的数据传递)。

以往的SplashActivity的设计图

这样看来上面这个设计流程可以这样表示: 
这里写图片描述

性能优且体验棒的Splash页的设计

从上面这个设计图来看,其中有些操作能不能去除呢?既能达到app启动速度的提高,也能对数据的预加载还能减去Splash和MainActivity之间不必要的数据传递和View的分开绘制。

答案是能的,既然SplashActivity和MainActivity分开进行操作还是不完美,那么可以考虑把它们合为一起,即:一开始还是显示MainActivity,SplashActivity变为SplashFragment,然后放一个FrameLayout作为根布局去显示SplashFragment界面,这样在SplashFragment显示时候利用显示的2~4s间的空隙时间做网络请求去加载数据,这样待SplashFragment显示完后再remove,这样将看到的是有内容的MainActivity,就不必再去等待网络请求去返回数据了。 
当然,这种方式是把load Splash View和ContentView合二为一了一起加载,这可能会影响应用的启动时间,这时我们可以用ViewStub延迟加载MainActivity中某些View从而减去这个影响。

如下设计: 
这里写图片描述

优化前后效果对比

这里为了测试,我把Splash页的delay时间都设为2.5s。 
优化前: 
这里写图片描述 
优化后: 
这里写图片描述 
优化后其实是把SplashActivity用Fragment显示,显示完后再remove,这样在显示的时候,MainActivity中还可以直接加载网络数据,这样在显示完SplashFragment后则直接显示主页了,而省去了ProgressBar进度条的网络加载过程。 
代码:

<code class="hljs axapta has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Handler mHandler = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Handler();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//...</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> SplashFragment splashFragment = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> SplashFragment();    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> FragmentTransaction transaction = getFragmentManager().beginTransaction();    transaction.replace(R.id.frame, splashFragment);    transaction.commit();   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//...</span>    mHandler.postDelayed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> DelayRunnable(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>, splashFragment, mProgressBar), <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2500</span>);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//...</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">DelayRunnable</span> <span class="hljs-inheritance" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span></span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Runnable</span> {</span>        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> WeakReference<Context> contextRef;        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> WeakReference<SplashFragment> fragmentRef;        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> WeakReference<ProgressBar> progressBarRef;        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> DelayRunnable(Context context, SplashFragment splashFragment, ProgressBar progressBar) {            contextRef = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> WeakReference<Context>(context);            fragmentRef = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> WeakReference<SplashFragment>(splashFragment);            progressBarRef = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> WeakReference<ProgressBar>(progressBar);        }        @Override        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> run() {            ProgressBar progressBar = progressBarRef.get();            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (progressBar != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>)                progressBar.setVisibility(View.GONE);            Activity context = (Activity) contextRef.get();            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (context != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {                SplashFragment splashFragment = fragmentRef.get();                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (splashFragment == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>)                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> FragmentTransaction transaction = context.getFragmentManager().beginTransaction();                transaction.remove(splashFragment);                transaction.commit();            }        }    }    @Override    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> onDestroy() {        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onDestroy();        mHandler.removeCallbacksAndMessages(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li></ul>

其中FrameLayout作为MainActivity的根布局用作SplashFragment的全屏显示。 
为了更优则可以考虑ViewStub,在SplashFragment显示时再进行加载额外的View。

关于耦合性,其实很低,Splash页面有专门一个SplashFragment去配置,而MainActivity只是控制它的加载与remove。

关于应用DelayLoad延迟加载的几种方式

1、View.postDelayed(); 
2、Handler.postDelayed(); 
3、getWindow().getDecorView().post(){Handler.postDelay()}

而前两种方式虽然都有Delay效果,但并不是真正Delay了我们设置的时间,而第三种方式才是正确的Delay了我们想要的时间,原因如下: 
关于Activity界面的启动,首先是在onCreate()方法中会对contentView、DecorView和ActionBar等进行初始化,比如:contentView进行inflate,我们便可以在这个方法中通过findViewById来找到对应的控件了,但是此时我们只是把那些对应的控件创建了一个对象而已,它们并没有add在界面上。而真正把contentView 添加到界面上的操作是在OnResume()方法执行时候,包括ViewRootImpl的初始化。而contentView的绘制会在onResume()方法执行完后的二次performTraversals()方法进行绘制。

所以要想达到DelayLoad懒加载效果,是在所有的View绘制完成后进行Delay效果,而上面的第一第二种方式都是在第一次performTraversals()后执行,该次只是为第二次调用performTraversals()方法做一些准备工作,这样就达不到准确的Delay效果了,因为第二次的performTraversals()就是真正的进行View的测量布局和绘制了,这肯定是需要时间的,所以第一和第二种方式Delay的时间是需要再减去这个View绘制的时间的。

如果是想在界面刚绘制完成后做一些事情,或者有些事情必须在UI绘制完成显示后做的话,那可以通过这个方法:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">        getWindow().getDecorView().post(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {                mHandler.post(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {                    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {                        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//do something</span>                    }                });            }        });</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

如果想Delay的话,可以这样:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">        getWindow().getDecorView().post(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {            <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {                mHandler.postDelayed(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {                    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {                        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//do something</span>                    }                },<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3000</span>);            }        });</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
0 0