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

  • 2019 年 10 月 5 日
  • 筆記

什麼叫冷啟動

拿起你的手機,把後台的任務都清理掉,然後再點擊你想要打開的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一開始打開的時候需要三四秒,使用了這個簡單粗暴法之後只需要一秒多就能打開了,是不是很爽?

總結

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

好啦,如此文章到這裡就結束了,如果你覺得不錯就給個讚唄?如果你覺得那裡值得改進的,請給我留言。一定會認真查詢,修正不足。謝謝。

希望讀到這的您能轉發分享和關注一下我,以後還會更新技術乾貨,謝謝您的支援!

轉發+點贊+關注,第一時間獲取最新知識點

Android架構師之路很漫長,一起共勉吧!

Tags: