Android 四大組件(二)Service

轉載請註明出處:http://blog.csdn.net/vnanyesheshou/article/details/73978804

一段時間不用,知識點就會忘,所以整理下一些基本的知識點,加深下印象,便於以後複習。這篇說一下Android中四大組件之一Service的使用。


1 Service簡介

Service是可以在後臺執行長時間運行的應用程序組件,不提供用戶界面。另一個應用程序組件可以啓動一個服務,即使用戶切換到另一個應用程序,它也將在後臺繼續運行。另外,組件可以綁定到一個服務來與它進行交互,甚至執行進程間通信(IPC)。例如,服務可以從後臺處理網絡事務,播放音樂,執行文件I / O或與內容提供商交互。

服務基本上可以採取兩種形式:

  • Started
    當應用程序組件(如Activity)通過調用startService()啓動服務時,服務將“啓動”。一旦啓動,服務可以在後臺無限期運行,即使啓動它的組件被銷燬。通常,啓動服務執行單個操作,並且不會將結果返回給調用者。例如,它可能會通過網絡下載或上傳文件。操作完成後,服務應該停止。
  • Bound
    當應用程序組件通過調用bindService()綁定到一個服務時,服務是“綁定的”。綁定服務提供客戶端 - 服務器接口,允許組件與服務交互,發送請求,獲取結果,甚至可以通過進程間通信(IPC)進行交互。只要綁定了一個應用程序組件,綁定的服務就會運行。多個組件可以同時綁定到服務,但是當所有組件都解除綁定時,服務將被銷燬。

雖然通常單獨討論這兩種類型的服務,但您的服務可以以兩種方式工作 - 它可以啓動(無限期運行)並允許綁定。這只是一個實現幾個回調方法的問題:onStartCommand()允許組件啓動它並onBind()允許綁定。

無論您的應用程序是啓動,綁定還是兩者兼容,任何應用程序組件都可以使用該服務(即使是單獨的應用程序),也可以以任何組件可以使用活動的方式啓動它Intent。但是,您可以將該服務聲明爲私有,在清單文件中,並阻止其他應用程序的訪問。

注意: 服務在主機進程的主線程中運行 - 服務不會創建自己的線程,並且不會在單獨的進程中運行(除非另有指定)。 這意味着,如果您的服務將進行任何CPU密集型工作或阻塞操作(如MP3播放或網絡連接),則應在服務中創建一個新的線程來完成此工作。 通過使用單獨的線程,您將降低應用程序不響應(ANR)錯誤的風險,並且應用程序的主線程可以保留專用於與您的活動的用戶交互。


2 創建Service

創建服務,必須創建一個Service(或其一個現有子類)的子類。在實現中,您需要覆蓋處理服務生命週期關鍵方面的一些回調方法,並提供一種機制,使組件綁定到服務(如果適用)。應該覆蓋的最重要的回調方法是:

  • onStartCommand()
    當另一個組件(如Activity)通過調用startService()請求啓動該服務時,系統將調用此方法。一旦執行此方法,該服務將啓動並可以無限期地在後臺運行。如果您實現這方法,您的責任是通過調用stopSelf()或stopService()停止服務。(如果只想提供綁定,則不需要實現此方法。)
  • onBind()
    當另一個組件通過調用bindService()與服務綁定時,系統會調用此方法。在實現此方法時,必須提供一個客戶端用於與服務通信的接口,方法是返回IBinder。您必須始終實現此方法,但如果不想允許綁定,則應返回null。
  • onCreate()
    系統調用該方法時,在首次創建服務,執行一次性建立過程(它在onStartCommand()或 onBind()調用之前)。如果服務已經運行,則不會調用此方法。
  • onDestroy()
    當服務不再使用並被銷燬時,系統調用此方法。應該實現這一點,以清理任何資源,如線程,註冊的聽衆,接收者等。這是服務接收的最後一個呼叫。
public class ExampleService extends Service {
    private static String TAG = "ExampleService";
    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG,"onCreate");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "onStartCommand");
        return START_STICKY;
    }
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"onBind");
        return null;
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG,"onDestroy");
    }
}

如果組件通過調用startService()(其導致調用onStartCommand())啓動服務,則服務將保持運行,直到它停止自身stopSelf()或通過調用停止它stopService()。
請注意,onStartCommand()方法必須返回一個整數。整數是一個值,描述系統在系統殺死服務時如何繼續服務。返回值onStartCommand()必須是以下常量之一:

  • START_NOT_STICKY  
    如果系統在onStartCommand()返回後殺死了服務,並且沒有待處理的intent,則會將Service從啓動狀態中刪除,並且不會重新創建服務了,直到明確的調用(Context.startService(Intent))。 當服務不再是必需的,並且應用程序能夠簡單地重啓那些未完成的工作時,這是避免服務運行的最安全的選項。 
     
  • START_STICKY
    如果系統在onStartCommand()返回後殺死了服務,則將重新創建服務並調用onStartCommand(),但不會再次傳入上一個intent, 而是用null intent來調用onStartCommand() 。除非有待處理的intent啓動服務,在這種情況下,這些intent會繼續傳遞。這適用於不執行命令但無限期運行並等待工作的媒體播放器(或類似服務)。
     
  • START_REDELIVER_INTENT
    如果系統在onStartCommand()返回後殺死了服務,則將重新創建服務並調用onStartCommand()(傳遞上一個發送給服務的intent),任何待處理的intent也都會依次送入。這適用於那些需要立即恢復工作的活躍服務,比如下載文件。

如果一個組件調用 bindService()創建服務(和onStartCommand()被不叫),那麼服務只只要組件綁定到它運行。一旦服務從所有客戶端解除綁定,系統就會銷燬它。

Android系統只會在內存不足時強制停止服務,並且必須爲具有用戶焦點的活動恢復系統資源。如果服務被綁定到具有用戶焦點的活動,則不太可能被殺死,並且如果該服務被聲明在前臺運行(稍後討論),則幾乎不會被殺死。否則,如果服務啓動並長時間運行,系統會隨着時間的推移降低後臺任務列表中的位置,並且服務將非常容易被殺死 。

3 在清單中聲明服務

像Activity(和其他組件)一樣,必須在清單文件中聲明應用程序的的所有服務。
要聲明您的服務,請添加元素作爲元素的子 元素。例如:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

可以在元素中包含其他屬性,例如啓動服務所需的權限以及服務應運行的進程等進程。該android:name 屬性是唯一必需的屬性,它指定服務的類名。

android:name---服務類名
android:label --- 服務的名字,如果此項不設置,那麼默認顯示的服務名則爲類名
android:icon----服務的圖標
android:permission-申明此服務的權限,這意味着只有提供了該權限的應用才能控制或連接此服務
android:process--表示該服務是否運行在另外一個進程,如果設置了此項,那麼將會在包名後面加上這段字符串表示另一進程的名字
android:enabled--如果此項設置爲 true,那麼 Service 將會可以被系統啓動,false,表示此Service不可以被啓動(也就是不能使用)。不設置默認此項爲true(網上好多person都說默認值位false,這是不對的。)
android:exported--表示該服務是否能夠被其他應用程序所控制或連接,不設置默認此項爲 false 

爲了確保您的應用程序安全,始終在啓動或綁定您時使用明確的意圖,Service並且不爲服務聲明意圖過濾器。如果關鍵是您允許開始使用哪些服務的模糊性,您可以爲您的服務提供意圖過濾器,並從中排除組件名稱Intent,然後您必須爲intent設置包setPackage(),這樣可以確定目標服務。

另外,您可以通過包含android:exported 屬性和設置爲”false”來確保您的服務僅適用於您的應用。即使使用明確的意圖,這有效地阻止其他應用程序啓動您的服務。


4 開始服務

諸如Activity之類的應用程序組件可以通過調用startService()並傳遞一個指定服務的Intent來啓動服務,幷包括要服務使用的任何數據。該服務Intent在onStartCommand()方法中接收到該intent。

Intent intent = new Intent(this, ExampleService.class);
startService(intent);

該startService()方法立即返回,Android系統調用該服務的onStartCommand()方法。如果服務尚未運行,則系統首先呼叫onCreate(),然後調用onStartCommand()。

當服務啓動時,它具有獨立於啓動服務的組件的生命週期,並且服務可以無限期地在後臺運行,即使啓動它的組件被銷燬。started的服務必須管理自己的生命週期。也就是說,系統不會停止或銷燬服務,除非它必須恢復系統內存,並且服務在onStartCommand()返回後繼續運行。因此,服務應該通過調用stopSelf()停止自己當完成工作時,或者另一個組件可以通過調用stopService()來停止它。


5 綁定服務

應用程序組件通過調用bindService()以創建長期連接來綁定的服務。
當您希望通過應用程序中的Activity和其他組件通過service進行交互,或通過進程間通信(IPC)將某些應用程序的功能暴露給其他應用程序時,應創建綁定服務。
要創建bound的服務,您必須實現onBind()回調方法來返回一個IBinder,IBinder用於定義與服務通信的接口。其他應用程序組件可以調用bindService()來檢索該接口並開始調用該服務的方法。 該服務僅用於爲與其綁定的應用程序組件提供服務,因此當沒有組件綁定到服務時,系統會將其銷燬。
要創建綁定的服務,首先要做的是定義一個接口,指定客戶端如何與服務進行通信。服務和客戶端之間的這個接口必須是一個實現,IBinder是您的服務必須從onBind()回調方法返回的。一旦客戶端收到IBinder,它可以開始通過該接口與服務進行交互。
多個客戶端可以一次綁定到該服務。當客戶端完成與服務的交互時,它會調用unbindService()解除綁定。一旦沒有客戶端綁定到服務,系統會銷燬該服務。

實現綁定服務有多種方法,並且實現比起始服務更復雜,下一篇講一下其多種方法。


6 service的生命週期

這裏寫圖片描述
Service生命週期(從創建到銷燬時)可以遵循兩個不同的路徑:

  • start Service
    當另一個組件調用startService()時,創建該服務。然後該服務無限期地運行,並且必須通過調用來停止自身stopSelf()。另一個組件也可以通過調用來停止服務stopService()。當服務停止時,系統會銷燬它
  • bind Service
    當另一個組件(客戶端)調用bindService()時,創建該服務。然後,客戶端通過IBinder接口與服務進行通信。客戶端可以通過調用來關閉連接 unbindService()。多個客戶端可以綁定到同一個服務,當它們全部解除綁定時,系統會銷燬該服務。(服務不需要自行停止。)

這兩條路徑並不完全分開。也就是說,您可以綁定到已經通過startService()啓動的Service。例如,背景音樂Service可以通過調用startService()啓動與Intent標識要播放的音樂。後來,可能當用戶想要對播放器進行一些控制或獲取關於當前歌曲的信息時,Activity可以通過調用bindService()來綁定到服務。在這種情況下,stopService()或者stopSelf()實際上並不停止服務,直到所有客戶端解除綁定。

參考文章:http://blog.csdn.net/zrf1335348191/article/details/70142992


歡迎掃一掃關注我的微信公衆號,定期推送優質技術文章:

這裏寫圖片描述

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