【Android】Service 生命週期

原文鏈接:http://www.roiding.com/index.php/archives/187


作爲一款多任務操作系統,如果不能運行後臺服務,顯然說不過去,Android 當然提供了運行後臺程序的方法。而且非常簡單易用,只不過有一些小問題需要注意,這個主題分爲兩部分,第一部分是如何實現一個Service以及他的生命週期,第二部分是對於一個個後臺服務應該注意的事項。我們開始吧!

創建服務類

所謂的服務,在Android裏被稱做 Service,只要繼承 android.app.Service 這個抽象類,並且實現其中幾個方法就可以了。

裏邊必須實現的一個方法是 onBind(Intent intent) ,他具體是做什麼的我們下邊講。還有兩個重要的回調函數需要覆蓋,onCreate() 和 onDestroy()。跟 Actitivty 類似,在創建和銷燬 Service 時回調這兩個函數,達到初始化或退出前保存狀態。

服務的生命週期

有了 Service 類我們如何啓動他呢,有兩種方法:

  • Context.startService()
  • Context.bindService()

在同一個應用任何地方調用 startService() 方法就能啓動 Service 了,然後系統會回調 Service 類的 onCreate() 以及 onStart() 方法。這樣啓動的 Service 會一直運行在後臺,直到 Context.stopService() 或者 selfStop() 方法被調用。另外如果一個 Service 已經被啓動,其他代碼再試圖調用 startService() 方法,是不會執行 onCreate() 的,但會重新執行一次 onStart() 。

另外一種 bindService() 方法的意思是,把這個 Service 和調用 Service 的客戶類綁起來,如果調用這個客戶類被銷燬,Service 也會被銷燬。用這個方法的一個好處是,bindService() 方法執行後 Service 會回調上邊提到的 onBind() 方發,你可以從這裏返回一個實現了 IBind 接口的類,在客戶端操作這個類就能和這個服務通信了,比如得到 Service 運行的狀態或其他操作。如果 Service 還沒有運行,使用這個方法啓動 Service 就會 onCreate() 方法而不會調用 onStart()。

 

與 Service 通信並且讓它持續運行

如果我們想保持和 Service 的通信,又不想讓 Service 隨着 Activity 退出而退出呢?你可以先 startService() 然後再 bindService() 。當你不需要綁定的時候就執行 unbindService() 方法,執行這個方法只會觸發 Service 的 onUnbind() 而不會把這個 Service 銷燬。這樣就可以既保持和 Service 的通信,也不會隨着 Activity 銷燬而銷燬了。

 

提高 Service 優先級

Android 系統對於內存管理有自己的一套方法,爲了保障系統有序穩定的運信,系統內部會自動分配,控制程序的內存使用。當系統覺得當前的資源非常有限的時候,爲了保 證一些優先級高的程序能運行,就會殺掉一些他認爲不重要的程序或者服務來釋放內存。這樣就能保證真正對用戶有用的程序仍然再運行。如果你的 Service 碰上了這種情況,多半會先被殺掉。但如果你增加 Service 的優先級就能讓他多留一會,我們可以用 setForeground(true) 來設置 Service 的優先級。

爲什麼是 foreground ? 默認啓動的 Service 是被標記爲 background,當前運行的 Activity 一般被標記爲 foreground,也就是說你給 Service 設置了 foreground 那麼他就和正在運行的 Activity 類似優先級得到了一定的提高。當讓這並不能保證你得 Service 永遠不被殺掉,只是提高了他的優先級。

有一個方法可以給你更清晰的演示,進入 $SDK/tools 運行命令

返回的一大堆東西,觀察 oom_adj 的值,如果是大於 8 一般就是屬於 backgroud 隨時可能被幹掉,數值越小證明優先級越高,被幹掉的時間越晚。你看phone的程序是 -12 說明電話就是電話,其他什麼都幹了了,也的能接電話對吧。另外還有一個 -100 的,更邪乎因爲是 system 如果他也完蛋了,你得系統也就掛了,嘿嘿。

 

用其他方式啓動 Service

其實不光能從 Activity 中啓動 Service ,還有一個很有用的方法是接收系統的廣播,這就要用到 Receiver 。在 Mainfest 文件中配置你得 Receiver 能接收什麼樣的廣播消息,那麼即使你得程序沒有顯示給用戶,你的 Service 也能啓動。你要做的就是繼承 android.content.BroadcastReceiver ,然後實現 onReceive(Context context, Intent intent) 方法,就可以啓動你得 Service 了。這裏不能 bindService 因爲一個 Receiver 是一個短暫存在的對象,所以 bind 是沒有什麼意義的。

資源消耗

大家都說 G1 的電池太不抗用,這個問題其實我看來跟多是軟件的問題。1150毫安的電池不算大,但也不算小了,考慮到 500mhz 的 CPU 還是非常耗電的。因爲一個 Service 要長時間後臺運行,所以如果你得 Service 太過於消耗資源那電池更用不了多久了。

對於這個問題我有一點點考慮,和大家分享一下。因爲一般 Service 都會啓動另外的線程不斷循環作一些操作,循環頻率不易太高。也不要做太過於耗費資源的操作,特別是CPU資源,因爲後臺 Service 用戶看不到,會比較莫名奇妙。具體可以結合 top 以及 logcat 監測使用情況。LOG中如果虛擬機頻繁的 GC 應該也說明程序還有很大改進的餘地。因爲GC 也是很耗費CPU的。可能這些不光 Service 應該注意,只要是移動設備都應該考慮,才能給你的用戶最佳的體驗。


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