App冷啟動,你還要我怎樣?

LashawndaBr 7年前發布 | 23K 次閱讀 安卓開發 Android開發 移動開發

什么叫冷啟動

拿起你的手機,把后臺的任務都清理掉,然后再點擊你想要打開的app圖標,這個時候,就是所謂的app冷啟動了。有人肯定會說,有冷啟動那不是還有熱啟動?對的,當你退出app的時候,沒把后臺的任務清理,并且系統沒有把這個app的進程服務給干掉,然后你點擊這個app的圖標再次進入的時候,這就是熱啟動了。

背景

有時候,你在打開一個app的時候會發現,你點擊了這個app的圖標,打開了之后會出現一段時間的白屏或者圖標卡頓了一會再進入app界面,這個時候你就會吐槽了,為什么會那么卡的?難道是我的手機永久了變卡的原因嗎?并不是的,這是因為app的冷啟動時間過長的原因造成app進入假死狀態了。這也是我們本篇文章所要優化的。

解決

我們先來解決打開app的時候閃白屏的這個問題。

首先我們得知道為什么會出現這個白屏的,在AndroidManifest.xml配置文件里面,你會看到你的LAUNCHER activity的配置

<activity    
    android:name=".StartPageActivity"    
    android:screenOrientation="portrait">    
        <intent-filter>        
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

如何你的LAUNCHER activity的配置是這樣的話,那么恭喜你,打開app的時候就會出現白屏了。那么,怎么配置才可以解決這個問題呢?

我們先添加一個Android Theme

<style name="AppBlackTheme" parent="Theme.AppCompat.Light.NoActionBar">    
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
</style>

這個主題很簡單,就是設置為透明的,然后我們再把這個主題添加到剛剛的LAUNCHER activity上。

<activity    
    android:name=".StartPageActivity"    
    android:theme="@style/AppBlackTheme"
    android:screenOrientation="portrait">    
        <intent-filter>        
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

這個時候你再打開你的app,就會發現不會再閃白屏了,是不是非常的簡單呢?這里效果圖我后期再進行添加了,先把代碼和原理在這里說清楚了。

隨著app的功能不斷完善,業務的不斷發展,接入的第三方服務越來越多,你的app將變得越來越龐大,這個時候你就會發現,當你想進入app的時候,點擊了圖標,就會發現進入app的時候變得更長了,等待的時候也變得更長了,而且點擊了圖標之后沒有立刻做出反應,而是進入到假死的狀態了,當你等待超過了5秒再操作手機的時候,又會出現另一個問題了:ANR(應用程序無響應),這個就是我們這篇文章所要解決的最重要的問題了。

問題所在

后臺無app殘留的進程服務,重新打開app的時候,從初始化application,結束后再到歡迎界面,很多情況下,就是因為初始化application的時間過長導致了app假死的狀態,然后再導致ANR的,所以我們就要優化application的初始化時間,如何去縮短初始化的時間,讓app運行得更加流暢。

方法一:IntentService

簡單說,IntentService是繼承于Service并處理異步請求的一個類,在IntentService內有一個工作線程來處理耗時操作,啟動IntentService的方式和啟動傳統Service一樣,同時,當任務執行完后,IntentService會自動停止,而不需要我們去手動控制。另外,可以啟動IntentService多次,而每一個耗時操作會以工作隊列的方式在IntentService的onHandleIntent回調方法中執行,并且,每次只會執行一個工作線程,執行完第一個再執行第二個,以此類推。而且,所有請求都在一個單線程中,不會阻塞應用程序的主線程(UI Thread),同一時間只處理一個請求。

看到IntentService的介紹,我們就想,可以不可以把耗時的初始化都丟到這里來呢?

public class InitializeService extends IntentService {    
    private static final String ACTION_INIT_WHEN_APP_CREATE = "com.youcheyihou.iyoursuv.service.action.INIT";    
    public InitializeService() {        
        super("InitializeService");    
    }    
    public static void start(Context context) {        
        Intent intent = new Intent(context, InitializeService.class);
        intent.setAction(ACTION_INIT_WHEN_APP_CREATE);        
        context.startService(intent);    
    }    
    @Override    
    protected void onHandleIntent(Intent intent) {        
        if (intent != null) {            
            final String action = intent.getAction();            
            if (ACTION_INIT_WHEN_APP_CREATE.equals(action)) {               
                //初始化
            }        
        }    
    }
}

我們看到InitializeService.java的代碼中,有一個onHandleIntent的方法,這個就是根據不同action來進行操作的,所以我們可以通過在onHandleIntent中來初始化一些耗時的操作,然后在application中onCreate中執行就行了,是不是很簡單?下來你們可以試一下哦。

那么問題來了,有人會說,我怎么知道IntentService什么時候初始化完啊?而且這個是異步的,如何還沒初始化完app就進入了主界面,就會出現第三方庫或者其他異常了啊?

是的,我們無法確定什么時候確定什么時候能初始化完,所以這些問題我們始終都會遇到,比如我在項目中使用的時候就出現過,有一些第三方庫就是必須在application創建的時候進行初始化,進入到app才可以使用的情況(ps:其實這樣的第三方庫真的是腦殘,為什么非要在application中初始化呢?你的庫初始化好了,我的app的用戶體驗就下降了)。那么,還有其他方法去解決初始化時間的問題嗎?那肯定有啦,剛剛不是說了是方法一嗎?現在就開始介紹方法二了。

方法二:簡單粗暴法

何為簡單粗暴法呢?且聽我慢慢講解。既然大部分第三方庫和資源要在application中初始化,那就讓它初始化嘛,但是這個前提是要先進入我們的歡迎界面StartPageActivity,然后再初始化。啊?這里是不是搞得頭暈腦脹了,剛剛不是說了先創建application再跳轉到StartPageActivity的嗎?怎么又反過來了,別急,我們慢慢來說,不過首先你的項目要集成了EventBus,而且你要會用EventBus哦。

上圖是方法二app冷啟動的打開流程圖,這個流程我就不說了,自己看圖吧,這里代碼也沒什么還寫,無非就是寫EventBus的發送事件和處理事件,這個也不用上代碼了吧?可以實踐一下,這個也很簡單的,有人會說,這個能優化的時間有多少啊?我大概測試了一下,優化的空間還是比較大的,可以縮短50%的時間左右,也就是說如果你的app一開始打開的時候需要三四秒,使用了這個簡單粗暴法之后只需要一秒多就能打開了,是不是很爽?

總結

其實,我一直都這樣認為的,代碼是死的,但是人是活的,所以我們可以使用很多簡單粗暴的方法去解決一下比較頑固的問題,不要一味說什么不符合邏輯不符合代碼規范(不過一些最基本的代碼規范還是要遵循的,因為代碼寫出來不只是給自己看的),發散思維,總會有一些方法會被你找到去解決遇到的問題的。共勉!

 

來自:http://www.jianshu.com/p/84983a3bdbff

 

 本文由用戶 LashawndaBr 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!