Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android性能優化之Splash頁應該這樣設計

Android性能優化之Splash頁應該這樣設計

編輯:關於Android編程

目前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進度條的網絡加載過程。
代碼:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;"> private Handler mHandler = new Handler(); //... final SplashFragment splashFragment = new SplashFragment(); final FragmentTransaction transaction = getFragmentManager().beginTransaction(); transaction.replace(R.id.frame, splashFragment); transaction.commit(); //... mHandler.postDelayed(new DelayRunnable(this, splashFragment, mProgressBar), 2500); //... static class DelayRunnable implements Runnable { private WeakReference contextRef; private WeakReference fragmentRef; private WeakReference progressBarRef; public DelayRunnable(Context context, SplashFragment splashFragment, ProgressBar progressBar) { contextRef = new WeakReference(context); fragmentRef = new WeakReference(splashFragment); progressBarRef = new WeakReference(progressBar); } @Override public void run() { ProgressBar progressBar = progressBarRef.get(); if (progressBar != null) progressBar.setVisibility(View.GONE); Activity context = (Activity) contextRef.get(); if (context != null) { SplashFragment splashFragment = fragmentRef.get(); if (splashFragment == null) return; final FragmentTransaction transaction = context.getFragmentManager().beginTransaction(); transaction.remove(splashFragment); transaction.commit(); } } } @Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacksAndMessages(null); }

其中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繪制完成顯示後做的話,那可以通過這個方法:

        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        //do something
                    }
                });
            }
        });

如果想Delay的話,可以這樣:

        getWindow().getDecorView().post(new Runnable() {
            @Override
            public void run() {
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //do something
                    }
                },3000);
            }
        });
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved