之前幾篇文章簡單梳理了在Android系統的四大元件之一,最主要的介面Activity
中,使應用程式與使用者進行互動響應的相關知識點,那對於應用程式中不需要與使用者互動的邏輯,又要用到哪些內容呢?本文開始將介紹應用程式無需介面互動的內部互動相關知識點,首先從另外一個四大元件之一的服務Service
開始。
在清單檔案一文的元件宣告中,已經知道服務Service
與介面Activity
一樣,都要在清單檔案中註冊宣告。同樣的,每個註冊宣告的服務Service
類向上追溯都必須繼承自android.app.Service父類,因此服務Service
也有自己的生命週期。
生命週期
Service
主要負責應用程式中不需要介面展示或互動的長時間操作,像是播放音樂,網路請求等都是可以在服務Service
中完成的。與介面Activity
的生命週期一樣,在服務Service
的宣告週期內不允許執行耗時操作,所以,雖然服務Service
中可以進行長時間操作,但是仍然需要將這部分耗時操作放入非Android系統主執行緒中。
(呼叫構造方法)物件例項化
首次啟動新的服務Service
時,系統會申請記憶體空間儲存該服務Service
的例項化物件。服務Service
有兩種啟動方式,其一與介面Activity
一樣需要藉助意圖Intent
物件,呼叫上下文環境Context
物件的startService(Intent service)
啟動。
其二是程序間通訊時所用的方式,不僅要藉助意圖Intent
物件,還要使用實現android.content.ServiceConnection介面的物件,進而呼叫上下文環境Context
物件的bindService(Intent service, ServiceConnection conn, int flags)
方法,而引數三 flags 標記了啟動該服務Service
時所繫結的模式,通常使用Context.BIND_AUTO_CREATE
標記會自動建立當前繫結的服務Service
。除此之外,還可以按位或的形式追加其他標記,例如追加|Context.BIND_NOT_FOREGROUND
標記當前繫結服務Service
為較低優先順序的後臺服務,在手機息屏或高能耗時,系統會優先殺死低優先順序的服務;而追加|Context.BIND_IMPORTANT
標記可以提升繫結服務Service
的優先順序為前臺服務,在手機息屏或高能耗時,只要當前應用程式存活,當前服務Service
就不會被殺死;如果追加|Context.BIND_ABOVE_CLIENT
標記當前繫結服務Service
的優先順序要高於當前應用程式,當手機息屏或高能耗時,系統可能會先殺死應用程式,但是當前服務Service
仍然存活。
Android系統為不同程序間的通訊提供了一套AIDL語言規範,詳情將在以後的文章中介紹,這裡只需瞭解在實現ServiceConnection
介面中,要重寫兩個方法,分別是在程序通訊介面與服務Service
連線成功後回撥的onServiceConnected(ComponentName name, IBinder service)
方法,和連線斷開之後回撥的onServiceDisconnected(ComponentName name)
方法。
上述兩種啟動方式,都會觸發系統在當前應用程式的清單檔案中查詢對應註冊過的服務Service
,在找到之後,就會建立其例項化物件,如果在清單檔案中沒有找到對應的服務Service
,將不會有任何錯誤或異常。
與啟動未註冊的服務
Service
不同的是,當呼叫startActivity()
系列方法啟動一個沒有在清單檔案中註冊過的介面Activity
時,系統通常會丟擲android.content.ActivityNotFoundException異常。
(呼叫attachBaseContext(Context base))載入執行環境
由於Service
也是android.content.ContentWrapper
的子類,所以系統在建立服務Service
的例項化物件後,也會優先對其載入上下文執行環境,將引數 base 作為當前應用程式的Context
物件與該服務Service
繫結。在該方法被呼叫之後的任意位置,就可以通過呼叫getBaseContext()
等系列方法獲取並使用當前服務Service
所在的上下文環境了。
(呼叫onCreate())服務建立
在建立服務Service
並載入執行環境之後,系統會優先呼叫該方法,表示當前服務已經完成建立。可以重寫該方法執行一些服務內部使用的資源初始化操作。在執行完該方法之後,就標誌著當前服務Service
建立成功了,之後會一直處於執行狀態,同時根據上述啟動方式的不同,呼叫不同的生命週期方法。
(呼叫onStartCommand(Intent intent, int flags, int startId))服務啟動
如果是通過上述啟動方式一啟動的服務Service
,每呼叫一次startService()
,系統都會呼叫一次該方法。
其中引數 intent 接收每次啟動服務所傳入的Intent
意圖。
引數 flags 標記當前服務多次啟動狀態,一般預設是 0 ;當該服務Service
被首次呼叫該方法且成功返回Service.START_REDELIVER_INTENT=3
後,莫名被系統殺死,之後再次啟動該服務時,標記引數則是 Service.START_FLAG_REDELIVERY=1 ;如果該服務Service
被首次呼叫該方法並未返回結果,系統將會再次嘗試呼叫該方法,標記引數則為 Service.START_FLAG_RETRY=2 。
引數 startId 作為系統唯一值,以此標記當前服務Service
。
最終返回指定的int
型別,如果返回預設的Service.START_STICKY_COMPATIBILITY=0
,當系統殺死該服務Service
後,再次呼叫startService()
將不會再被系統回撥該方法;另外如果返回Service.START_STICKY=1
,在系統殺死該服務Service
後,再次呼叫startService()
將會被系統重新建立例項化並回調該方法。
(呼叫onBind(Intent intent))服務繫結
如果是通過上述啟動方式二啟動的服務Service
,在首次呼叫bindService()
後,系統會呼叫該方法,而之後如果多次呼叫bindService()
,只有在當前服務Service
已經執行完onUnbind()
解綁的生命週期方法,並在解綁方法中返回 false 時,系統才會回撥該方法。引數 intent 接收繫結服務所傳入的Intent
意圖,最終返回android.os.IBinder介面的實現類物件。返回結果可以在bindService(Intent service, ServiceConnection conn, int flags)
方法的引數二conn.onServiceConnected(ComponentName name, IBinder service)
方法中接收,也就是其中的引數二IBinder
型別的 service。
服務解綁(呼叫onUnbind(Intent intent))
如果是通過上述啟動方式二啟動的服務Service
,可以在bindService()
繫結服務Service
位置相對應的位置,呼叫unbindService()
解綁服務Service
。之後系統會回撥該方法,同樣的藉助引數Intent
意圖例項來指定要解綁的指令資訊。
服務重綁(呼叫onRebind(Intent intent))
如果是通過上述啟動方式二啟動的服務Service
,如果當前服務Service
已經執行完解綁生命週期,並在onUnbind()
方法中返回 true 時,系統將會呼叫該方法以使用原有的IBinder
物件重新綁定當前服務Service
,因此該方法不需要返回值。其引數 intent 接收繫結服務所傳入的Intent
意圖。最終返回值boolean
型別,以標記當前服務再次被繫結時是否使用原有繫結過的IBinder
物件。
服務銷燬(呼叫onDestroy())
啟動之後的服務Service
會一直處於執行狀態,直到系統可能因能耗過過而殺死低優先順序的程序時,當前服務Service
將會被動殺死,或者當前服務Service
主動呼叫程式碼停止執行。與上述兩種啟動方式對應,服務Service
也有兩種停止方式。
其一對應於startService()
啟動的服務,呼叫上下文環境Context
物件的stopService(Intent service)
方法停止執行,或者呼叫當前服務Service
物件的stopSelf()
方法也可以停止執行自身服務。
其二對應於bindService()
繫結的服務,呼叫上下文環境Context
物件的unbindService(ServiceConnection conn)
方法解除繫結。由於繫結該服務的可以有多個ServiceCOnnection
連線,所以必須每個bindService()
繫結服務的位置都對應呼叫unbindService()
方法主動解綁,以防止出現記憶體洩漏或資源佔用等誤操作。
在服務Service
所有繫結已解綁或主動停止執行後,系統最終會呼叫該方法,之後將銷燬記憶體中建立的該服務Service
例項化物件。因此可以重寫該方法,對應於onCreate()
中申請的初始化資源在該方法中釋放掉。
服務Service
的生命週期與介面Activity
有些類似,這也保證了在其中可以執行無使用者互動的操作,那麼針對這種應用場景還需要怎麼構建子執行緒操作呢?而且服務Service
的設計還可以進行程序間通訊。具體又是如何編寫程式碼搭建程序間的溝通橋樑呢?敬請期待後續文章。