Android Service 你真的能應答自如了嗎?面試必備知識點複習起來~

Android Service 你真的能應答自如了嗎?面試必備知識點複習起來~

今天我們來探討一下 Android 四大組件的重要組成部分:Service。

Service 有多重要?

之前在「蘭柳學」的文章中看到這樣一個場景,挺有意思的,先給大家分享一下,讓我們一起來看看對 Service 的無知到底會有多麻煩。

場景:如果一個應用要從網絡上下載一個文件,並在 Activity 上展示進度條,這個 Activity 要求是可以轉屏的。那麼在轉屏時 Actvitiy 會重啓,如何保證下載的進度條能正確展示進度呢?

不會 Service 的人,一般會想出來這樣的方案。

    1. 在轉屏前將進度緩存,轉屏後再讀出來。
    1. 使用 android:configChanges 設置,讓轉屏時 Activity 不銷燬和重建。

針對第 1 種方案,其實細想漏洞百出。首先,轉屏的過程中,我們知道 Activity 的重建算是比較耗時的,可能會有幾百毫秒甚至更久,這時候下載線程仍然在工作,進度肯定和保存時的進度不一致了,如何處理這個問題呢?

第 2 個方案,大家可以自己展開思考,實際的項目中可能會需要額外做一些事情來處理 ContentView 的橫豎佈局的問題。

如果採用 Service,你有什麼好主意呢?不妨在評論區給出。

一定聽過 Service 吧,它有幾種啓動方式?

Service 是一個專門在後臺執行長時間操作的類,它並不與用戶產生 UI 交互。它提供了兩種啓動方式。

  • started
    其它組件調用 startService() 啓動一個 Service。一旦啓動,Service 將一直運行在後臺,即使啓動這個 Service 的組件已經被銷燬。通常一個被 start 的 Service 會在後臺執行單獨的操作,也並不需要給啓動它的組件返回結果。只有當 Service 自己調用 stopSelf() 或者其它組件調用 stopService() 纔會終止。
  • bind
    其它組件可以調用 bindService() 來綁定一個 Service。這種方式會讓 Service 和啓動它的組件綁定在一起,當啓動它的組件銷燬的時候,Service 也會自動進行 unBind 操作。同一個 Service 可以被多個組件綁定,只有所有綁定它的組件都進行了 unBind 操作,這個 Service 纔會被銷燬。

當然,Service 還可以同時在上述兩種方式下運行。這涉及到 Service 的兩個回調方法的執行: onStartCommand()(通過 start 方式啓動一個 Service 時的回調方法。)、onBind() (通過 bind 方式啓動一個 Service 回調的方法)。

無論通過那種方式啓動 Service(start、bind、start & bind),任何組件(甚至其他應用的組件)都可以使用 Service。並通過 Intent 傳遞參數。當然,你也可以將 Service 在 AndroidMenifest.xml 文件中配置成私有的,不允許其他應用訪問。

android:exported 屬性設爲 false,表示不允許其他應用程序啓動本應用的組件,即便是顯式 Intent 也不行(even when using an explicit intent)。這可以防止其他應用程序啓動您的 Service 組件。

Service 的生命週期

一談到組件,我們總是喜歡去研究它的生命週期,而這時候用圖來展示肯定是最好的了。

Android Service 你真的能應答自如了嗎?面試必備知識點複習起來~

這兩條路徑並不是毫不相干的。當調用 startService() 去 start 一個 Service 後,你仍然可以 bind 這個 Service。比如:當播放音樂的時候,需要調用 startService() 啓動指定的音樂,當需要獲取該音樂的播放進度的時候,又需要調用 bindService(),在這種情況下,除非 Service 被 unbind,此前調用 stopService()stopSelf() 都不能停止該 Service。

這些生命週期方法在使用的時候並不需要調用各自的父類方法。

兩條生命週期路徑都可以包含兩個嵌套的生命週期:

  • 完整生命週期(entire lifetime):從 onCreate() 被調用,到 onDestroy() 返回。和 Activity 類似,一般在 onCreate() 方法中做一些初始化的工作,在 onDestroy() 中做一些資源釋放的工作。如,若 Service 在後臺播放一個音樂,就需要在 onCreate() 方法中開啓一個線程啓動音樂,並在 onDestroy() 中結束線程。

  • 活動生命週期(activity lifetime):從 onStartCommand()onBind() 回調開始,由相應的 startService()bindService() 調用。start 方式的活動生命週期結束就意味着完整證明週期的結束,而 bind 方式,當 onUnbind() 返回後,Service 的活動生命週期結束。

值得注意的是,無論是 startService() 還是 bindService() 啓動 Service,onCreate()onDestroy() 均會被回調。

Service 的 onCreate() 可以執行耗時操作嗎?

Service 運行在主線程中,它並不是一個新的線程,也不是新的進程,所以並不能執行耗時操作。

那如果要在 Service 中執行耗時操作,怎麼做?

我想基本所有人都能想到使用 Thread,事實上我們也經常這麼做。需要在主線程執行耗時操作,無非就是開一個線程,然後一陣混沌操作。當然,你還可以使用 AysncTaskHandlerThread 來替代 Thread 創建線程。

當然沒有問題,那還有其它更有意思的方式嗎?

有,當然有,IntentService 就是一個不錯的選擇。

紛繁複雜的 IntentService

Android Service 你真的能應答自如了嗎?面試必備知識點複習起來~

IntentService 繼承於 Service,若 Service 不需要同時處理多個請求,那麼使用 IntentService 將是最好選擇。你只需要重寫 onHandleIntent() 方法,該方法接收一個回調的 Intent 參數,你可以在方法內進行耗時操作,因爲它默認開啓了一個子線程,操作執行完成後也無需手動調用 stopSelf() 方法,onHandleIntent() 將會自動調用該方法。

使用 IntentService 的要點如下:

  • 默認在子線程中處理回傳到 onStartCommand() 方法中的 Intent;
  • 在重寫的 onHandleIntent() 方法中處理按時間排序的 Intent 隊列,所以不用擔心多線程(multi-threading)帶來的問題。
  • 當所有請求處理完成後,自動停止 Service,無需手動調用 stopSelf() 方法;
  • 默認實現了 onBind() 方法,並返回 null;
  • 默認實現了 onStartCommand() 方法,並將回傳的 Intent 以序列的形式發送給 onHandleIntent(),您只需重寫該方法並處理 Intent 即可。

小結

當我們知道了 Service 的用途,心中有一個 Service 相關的概念時,針對實際的場景還是要做具體的分析再決定是否使用 Service。因爲 Service 仍然是在主線程中調用,還是要開線程才能處理長時間的工作,Service 和 UI 的交互也讓這個方式變得不那麼簡便。如果你只需要在當前界面去做一些耗時操作,界面退出或改變時,工作也要停止,那麼這時直接使用 Thread(或者 AsyncTask, ThreadHandler)會更合適你。

最後對於程序員來說,要學習的知識內容、技術有太多太多,要想不被環境淘汰就只有不斷提升自己,從來都是我們去適應環境,而不是環境來適應我們!

這裏附上上述的技術體系圖相關的幾十套騰訊、頭條、阿里、美團等公司19年的面試題,把技術點整理成了視頻和PDF(實際上比預期多花了不少精力),包含知識脈絡 + 諸多細節,由於篇幅有限,這裏以圖片的形式給大家展示一部分。

相信它會給大家帶來很多收穫:

Android Service 你真的能應答自如了嗎?面試必備知識點複習起來~

Android Service 你真的能應答自如了嗎?面試必備知識點複習起來~

上述【高清技術腦圖】以及【配套的架構技術PDF】可以 加我wx:X1524478394 免費獲取!

當程序員容易,當一個優秀的程序員是需要不斷學習的,從初級程序員到高級程序員,從初級架構師到資深架構師,或者走向管理,從技術經理到技術總監,每個階段都需要掌握不同的能力。早早確定自己的職業方向,才能在工作和能力提升中甩開同齡人。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章