以前幾篇文章簡單梳理了在Android系統的四大組件之一,最主要的界面Activity
中,使應用程序與用戶進行交互響應的相關知識點,那對於應用程序中不須要與用戶交互的邏輯,又要用到哪些內容呢?本文開始將介紹應用程序無需界面交互的內部交互相關知識點,首先從另一個四大組件之一的服務Service
開始。html
在清單文件一文的組件聲明中,已經知道服務Service
與界面Activity
同樣,都要在清單文件中註冊聲明。一樣的,每一個註冊聲明的服務Service
類向上追溯都必須繼承自android.app.Service父類,所以服務Service
也有本身的生命週期。android
Service
主要負責應用程序中不須要界面展現或交互的長時間操做,像是播放音樂,網絡請求等都是能夠在服務Service
中完成的。與界面Activity
的生命週期同樣,在服務Service
的聲明週期內不容許執行耗時操做,因此,雖然服務Service
中能夠進行長時間操做,可是仍然須要將這部分耗時操做放入非Android系統主線程中。網絡
首次啓動新的服務Service
時,系統會申請內存空間存儲該服務Service
的實例化對象。服務Service
有兩種啓動方式,其一與界面Activity
同樣須要藉助意圖Intent
對象,調用上下文環境Context
對象的startService(Intent service)
啓動。app
其二是進程間通訊時所用的方式,不只要藉助意圖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
仍然存活。google
Android系統爲不一樣進程間的通訊提供了一套AIDL語言規範,詳情將在之後的文章中介紹,這裏只需瞭解在實現ServiceConnection
接口中,要重寫兩個方法,分別是在進程通訊接口與服務Service
鏈接成功後回調的onServiceConnected(ComponentName name, IBinder service)
方法,和鏈接斷開以後回調的onServiceDisconnected(ComponentName name)
方法。線程
上述兩種啓動方式,都會觸發系統在當前應用程序的清單文件中查找對應註冊過的服務Service
,在找到以後,就會建立其實例化對象,若是在清單文件中沒有找到對應的服務Service
,將不會有任何錯誤或異常。設計
與啓動未註冊的服務
Service
不一樣的是,當調用startActivity()
系列方法啓動一個沒有在清單文件中註冊過的界面Activity
時,系統一般會拋出android.content.ActivityNotFoundException異常。code
因爲Service
也是android.content.ContentWrapper
的子類,因此係統在建立服務Service
的實例化對象後,也會優先對其加載上下文運行環境,將參數 base 做爲當前應用程序的Context
對象與該服務Service
綁定。在該方法被調用以後的任意位置,就能夠經過調用getBaseContext()
等系列方法獲取並使用當前服務Service
所在的上下文環境了。htm
在建立服務Service
並加載運行環境以後,系統會優先調用該方法,表示當前服務已經完成建立。能夠重寫該方法執行一些服務內部使用的資源初始化操做。在執行完該方法以後,就標誌着當前服務Service
建立成功了,以後會一直處於運行狀態,同時根據上述啓動方式的不一樣,調用不一樣的生命週期方法。對象
若是是經過上述啓動方式一啓動的服務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()
將會被系統從新建立實例化並回調該方法。
若是是經過上述啓動方式二啓動的服務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。
若是是經過上述啓動方式二啓動的服務Service
,能夠在bindService()
綁定服務Service
位置相對應的位置,調用unbindService()
解綁服務Service
。以後系統會回調該方法,一樣的藉助參數Intent
意圖實例來指定要解綁的指令信息。
若是是經過上述啓動方式二啓動的服務Service
,若是當前服務Service
已經執行完解綁生命週期,並在onUnbind()
方法中返回 true 時,系統將會調用該方法以使用原有的IBinder
對象從新綁定當前服務Service
,所以該方法不須要返回值。其參數 intent 接收綁定服務所傳入的Intent
意圖。最終返回值boolean
類型,以標記當前服務再次被綁定時是否使用原有綁定過的IBinder
對象。
啓動以後的服務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
的設計還能夠進行進程間通訊。具體又是如何編寫代碼搭建進程間的溝通橋樑呢?敬請期待後續文章。