android service

來自:http://1622511.blog.51cto.com/1612511/568988

 Service是一個可以在後臺執行長時間操作的程序組件,它不提供用戶接口。一個應用程序可以啓動一個service,即使用戶切換到其它應用程序,它也會繼續在後臺運行。此外一個組件可以綁定到一個service來與它交互甚至是用戶進程之間的通信(IPC)。比如說,一個service或許處理網絡事務,播放音樂,執行文件I/O或者與一個content provider相互作用,所有的都在後臺進行。

Service通常採用兩種方式:

被啓動(started):

 當一個應用程序組件通過調用startService()啓動它時,這個service稱爲”started”。一旦被啓動,一個service就可以在後臺獨立的運行,即使啓動它的組件已經被destory。通常一個被啓動的service執行一項單獨的操作併爲呼叫者(caller)返回結果。比如說,它或許通過網絡下載或上傳一個文件。當操作完成時,這個service將自動停止。

被綁定(bound):

 當一個應用程序組件通過調用bindService()綁定到它上面時,這個service稱爲” bound”。一個綁定的service提供了一個客戶-服務接口來允許這個組件與service交互,發送請求,獲得結果甚至使用進程間通信來跨進程做這些。一個綁定的service一直運行直到有其他的組件綁定到它上面。多個組件可以一次性綁定到一個service,但是當它們所有的解綁定時,service將被銷燬。

 儘管本文檔常常單獨的討論這兩種方式,但是你的service都可以用這兩種方式。它可以被啓動(無限期運行)或者亦可以綁定。只取決於你是否實現了一對回調函數:onStartCommand()來允許組件啓動它以及onBind()允許綁定。

 無論你的應用程序是採用啓動,綁定還是兩者都有,任何程序組件都可以通過Intent使用這個service(甚至從一個單獨的程序),如同任何組件都可使用activity。然而你可以在manifest文件將這個service聲明爲私有並阻止其他程序的訪問。

 Caution:一個service在它的主進程中運行---service不會創建它自己的線程並且不會運行在單獨的進程(除非用別的方法指定)。這意味着,如果你的service將做一些CPU密集工作或者模塊化的操作(比如MP3重放或聯網),你應該爲service創建一個新的線程來做這些工作。通過使用單獨的線程,你可以減少Application Not Responding (ANR)錯誤的風險並且應用程序的主線程可以依然專注於用戶與你的activity的交互。

 


--------------------------------------------------------------------------------

Service基礎
 爲了創建一個service,你必須創建一個Service(或已存的子類)的子類。你還需要重寫一些回調函數,這些函數常處理service關鍵點以及實現綁定的機制。你需要重寫的幾個重要的回調函數是:

onStartCommand()

 當別的組件,如一個activity,調用startService()來請求的service被啓動時由系統調用。一旦該方法執行,service將啓動並在後臺無限期的運行。如果你實現它,當在service工作完成後使用stopSelf()或stopService()停掉它是你的責任。(如果你想使用綁定的方式,你無須實現這個方法。)

onBind()

 當一個組件通過調用bindService()想要與service(比如執行RPC)綁定時由系統調用。在你的實現中,你必須提供一個接口 讓客戶端使用來與service通訊,並返回一個IBinder。你必須總是實現這個方法,但是如果你不想綁定時可以返回null。

onCreate()

 當service被第一次創建時由系統調用,來執行一次性的設置步驟(在調用onStartCommand()或onBind()之前)。如果service已經運行,該方法不會被調用。

onDestory()

 當service不再使用並被銷燬時由系統調用。你的service必須實現這個方法來清空資源(比如線程,註冊的監聽器,receiver等)。如果一個組件通過調用startService()(這將導致調用onStartCommand())來啓動一個service,這個service將一直運行,直到它自己調用stopSelf()來停止或者別的組件調用stopService()來停止它。

 如果一個組件調用bindService()來創建這個service(onStartCommand()不會被調用),這個service一直運行直到有其他的組件綁定到它上面。一旦沒有客戶端綁定到這個service,系統就會destory它。

 當內存過低,系統必須爲用戶關注的activity回收資源時,Android系統可以強行停止一個service。如果這個service被綁定到用戶關注的activity時,它可能不會被kill。如果這個service被聲明爲run in the foreground,它將永遠都不會被kill。否則如果service是長時間操作,系統會隨着時間的推移降低其在task列表裏的位置並且這個service將變的容易被kill。---如果你的service被啓動,你必須設計好,能使系統很好的處理restart。如果系統kill了你的service,在資源變的可用時,系統會restart你的service(儘管這依然取決於你從onStartCommand()中返回的值)。,

 在下面的章節,你將看到如何創建各種類型的service以及如何從其他程序組件使用。

 

在manifest中聲明一個Service:

 如同activity,你必須在manifest文件中聲明所有的service。爲了聲明你的service,爲<application>元素添加一個<service>元素,例如:

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
<manifest ... >  
  ...   
  <application ... >  
      <service android:name=".ExampleService" />  
      ...   
  </application>  
</manifest>  
<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

 還有一些其它的屬性你可以包含到<service>元素來聲明一些特性,比如啓動service的權限,service應在哪個進程裏運行。

 正如一個activity,一個service可以定義intent filter來允許其它的組件通過implicit intent激活(invoke)service。通過聲明intent filter,在設備上安裝的其他程序的組件可以啓動你的service,只要你的service聲明的intent filter與其他應用程序傳遞給startService()的intent匹配。

 如果你打算局部使用你的service(其他應用程序不能使用),這時你不需要也不應該提供intent filter。沒有intent filter,你必須通過一個指定了service類名稱的intent來啓動該service。

 另外,如果你包含一個android:exported屬性並將其值設爲false,你可以確保你的service對你的程序是私有的。即使你的service提供了intent filter,這個屬性也會發揮作用。 


--------------------------------------------------------------------------------

創建一個 Started Service
 一個start service是指由其它組件通過調用startService()啓動的service,調用該方法會觸發service的onStartCommand()函數的調用。

當一個service被啓動,它就有了獨立於啓動它的組件的生命週期,service可以在後臺無限期的運行,即使啓動它的組件被銷燬。因此這個service必須在工作結束時自行調用stopSelf()結束自己,或者有其他的組件調用stopService()來停止它。

 一個應用程序比如activity可以通過調用startService()啓動service,需要傳遞給方法一個指明瞭service的Intent,並在其內部包含一些service使用的數據。這個service在onStartCommand()方法內接受到這個Intent。

 例如,設想一個activity需要將一些數據存儲到online數據庫。這個activity可以啓動一個companion service並通過傳遞給startService()方法的Intent將數據遞交給service。service在onStartCommand()方法內接受到這個Intent,連接到互聯網並執行數據庫事務。當事務完成,service停止它自己並被銷燬。

 Caution: 在默認情況下service與其聲明所在的應用程序程序在相同的進程中,且都在程序的主線程運行。所以在用戶與在同一程序中的activity交互的時候,如果你的service執行密集或者中斷性的操作,service將會降低activity的執行速度。爲了避免影響程序運行,你應該爲service另起一個新的線程。


通常有兩個類可以讓你來繼承來創建一個started service:

Service:

 這是所有service的基類。當你繼承這個類,你應該創建一個新的線程來做所有的service工作,因爲默認情況下下這個service使用你應用程序的主線程,這將降低你應用程序中運行的activity的效率。

IntentService:

 這個是Service的子類,它使用一個worker 線程逐個處理所有start請求。如果你不需要你的service同時處理多個請求,這將是最好的選擇。你所要做的就是實現onHandleIntent()方法,該方法爲每個啓動請求接收Intent,所以你可以做後臺工作。

下面的章節描述如何是用上面的類實現service。

 

繼承IntentService類:

 因爲大多數started service不需要處理同時處理多個請求(這實際上是一個危險的多線程方案),你使用IntentService的子類來實現你的service可能是最好的選擇。

IntentService將做以下內容:

 創建一個默認的worker線程來執行傳遞給onStartCommand()的所有intent,以與主線程分離。 
 創建一個工作隊列用來逐個傳遞intent給你的onHandleIntent()實現,所以你永遠不用擔心多線程。 
 當所有start請求處理後,stop所有的service,所以你無須調用stopSelf() 
 提供一個對onBind()的默認實現,並返回null 
 提供一個對onStartCommand()的默認實現來發送intent到工作隊列然後傳遞給onHandleIntent()實現。 
 所有這些事實表明你所需要做的所有事是實現onHandleIntent()來做由Intent提出的工作。(雖然你也需要爲service提供一個構造方法)

下面是一個IntentService的實現:

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
public class HelloIntentService extends IntentService {   
  /**   
   * 需要一個構造方法,並調用父類的IntentService(String),傳入worker 線程的名字.  
   */  
  public HelloIntentService() {   
      super("HelloIntentService");   
  }   
  /**  
   * IntentService 從啓動Service的intent的默認的worker線程調用這個方法,當這個方法返回時IntentService 
    * 恰當的時候stops 這個 service  
   */  
  @Override  
  protected void onHandleIntent(Intent intent) {   
      // 通常我們要在這裏做一些工作, 比如下載一個文件.   
      // 舉例, 只是 sleep 5 秒鐘.   
      long endTime = System.currentTimeMillis() + 5*1000;   
      while (System.currentTimeMillis() < endTime) {   
          synchronized (this) {   
              try {   
                  wait(endTime - System.currentTimeMillis());   
              } catch (Exception e) {   
              }   
          }   
      }   
  }   
}  
public class HelloIntentService extends IntentService {
  /** 
   * 需要一個構造方法,並調用父類的IntentService(String),傳入worker 線程的名字.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }
  /**
   * IntentService 從啓動Service的intent的默認的worker線程調用這個方法,當這個方法返回時IntentService
  * 恰當的時候stops 這個 service
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // 通常我們要在這裏做一些工作, 比如下載一個文件.
      // 舉例, 只是 sleep 5 秒鐘.
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}
 

 

 我們要做的只是提供一個構造方法並實現onHandleIntent()方法。

 如果你決定重寫其它的回調函數,比如onCreate(),onStartCommand()或者onDestory(),確保調用父類的實現,以便IntentService可以適當的處理worker線程的聲明。

 比如,onStartCommand()必須返回默認的實現:

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
@Override  
public int onStartCommand(Intent intent, int flags, int startId) {   
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();   
    return super.onStartCommand(intent,flags,startId);   
}  
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    return super.onStartCommand(intent,flags,startId);
}
 

 

 除了onHandleIntent(),你不需要調用父類的方法的是onBind()(但是如果你的service允許綁定,你只需要實現它)。

 在下一節,你將看到在繼承Service類時,相同類的service如何實現,它將需要更多的代碼,但是如果你需要同時處理start請求,這也許將是必須的。

 

繼承Service類:

 如果你需要service來執行多線程(而不是通過一個工作隊列處理start請求),這時你可以繼承Service類來處理每個Intent。

 爲了比較,下面的例子代碼是一個繼承Service類實現的方式,該方式與前面使用IntentService類的例子執行了相同工作。換句話說,爲每一個start請求,它使用一個worker線程來執行工作並一次只處理一個。

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
    public class HelloService extends Service {   
       private Looper mServiceLooper;   
    private ServiceHandler mServiceHandler;   
     // 從線程接收消息的Handler    
     private final class ServiceHandler extends Handler {   
        public ServiceHandler(Looper looper) {   
            super(looper);   
        }   
        @Override  
        public void handleMessage(Message msg) {   
          //通常我們要在這裏做一些工作, 比如下載一個文件.   
          //舉例, 只是 sleep 5 秒鐘.   
          long endTime = System.currentTimeMillis() + 5*1000;   
          while (System.currentTimeMillis() < endTime) {   
              synchronized (this) {   
                  try {   
                      wait(endTime - System.currentTimeMillis());   
                  } catch (Exception e) {   
                  }   
              }   
          }   
          // 用startId stop這個service, so that we don't stop   
          // service在處理其他期間   
          stopSelf(msg.arg1);   
      }   
  }   
  @Override  
  public void onCreate() {   
    // 啓動一個線程來運行service.注意我們創建了一個單獨的線程,因爲Service通常運行在主線程   
    // 我們也將優先將其運行在後臺,這樣CPU密集工作將不會阻斷我們的UI     
    HandlerThread thread = new HandlerThread("ServiceStartArguments",   
            Process.THREAD_PRIORITY_BACKGROUND);   
    thread.start();   
       
    // Get the HandlerThread's Looper and use it for our Handler    
    mServiceLooper = thread.getLooper();   
    mServiceHandler = new ServiceHandler(mServiceLooper);   
  }   
  @Override  
  public int onStartCommand(Intent intent, int flags, int startId) {   
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();   
      // 對每一個start請求,發送一個消息來啓動一項工作並傳遞一個start ID來標識當我們完成工作時哪個請求要被stop    
      Message msg = mServiceHandler.obtainMessage();   
      msg.arg1 = startId;   
      mServiceHandler.sendMessage(msg);   
         
      // If we get killed, after returning from here, restart   
      return START_STICKY;   
  }   
  @Override  
  public IBinder onBind(Intent intent) {   
      // We don't provide binding, so return null   
      return null;   
  }   
     
  @Override  
  public void onDestroy() {   
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();    
  }   
}  
 public class HelloService extends Service {
     private Looper mServiceLooper;
    private ServiceHandler mServiceHandler;
     // 從線程接收消息的Handler 
     private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
          //通常我們要在這裏做一些工作, 比如下載一個文件.
          //舉例, 只是 sleep 5 秒鐘.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // 用startId stop這個service, so that we don't stop
          // service在處理其他期間
          stopSelf(msg.arg1);
      }
  }
  @Override
  public void onCreate() {
    // 啓動一個線程來運行service.注意我們創建了一個單獨的線程,因爲Service通常運行在主線程
    // 我們也將優先將其運行在後臺,這樣CPU密集工作將不會阻斷我們的UI  
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    
    // Get the HandlerThread's Looper and use it for our Handler 
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }
  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
      // 對每一個start請求,發送一個消息來啓動一項工作並傳遞一個start ID來標識當我們完成工作時哪個請求要被stop 
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);
      
      // If we get killed, after returning from here, restart
      return START_STICKY;
  }
  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }
  
  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show(); 
  }
}
 

 

 如你所見,比起IntentService,你要做更多的事。然而因爲你自己處理每個onStartCommand()的調用,你可以同時執行多個請求。本例中沒有實現,但是如果你願意,你可以爲每個請求創建一個新的線程並立即運行它們(而不是等先前的請求結束)。

 注意onStartCommand()方法必須返回一個整型。這個整型是用來描述系統在kill Service時如何繼續這個service的值(如前面討論的,IntentService的默認實現爲你處理這些).onStartCommand()的返回值必須是下面中的一個:

START_NOT_STICKY:

 如果在onStartCommand()返回之後系統kill這個service,不要重新創建這個service,除非有intent提交。在不需要或你的應用程序可簡單restart任何未完成的工作時這是避免運行你的service的最佳選擇。

START_STICKY:

 如果在onStartCommand()返回之後系統kill這個service,重新創建service並調用onStartCommand(),但是不要傳遞最後一個Intent。系統調用傳入null實參的onStartCommand(),除非有待定(pending)Intent來start service,在此情況下,這些intent將被傳遞。

這適合於媒體播放器(或類似的Service),它們沒有在執行命令,但是無限期的運行並等待工作。

START_REDELIVER_INTENT

 如果在onStartCommand()返回之後系統kill這個service,重新創建service,調用onStartCommand()並傳遞給它遞交給service的最後一個intent。任何待定(pending)intent依次被遞交。這適合於積極的執行需要馬上返回的工作的service,比如下載一個文件。


啓動Service

 你可以在activity或其它應用程序組件中通過傳遞Intent(指明要啓動的service)給startService來啓動一個service。Android系統會調用service的onStartCommand()方法並傳遞一個Intent。

 比如,一個activity可以使用一個explicit intent 來啓動先前例子的service:

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
Intent intent = new Intent(this, HelloService.class);   
startService(intent);  
Intent intent = new Intent(this, HelloService.class);
startService(intent);
 

 startService()方法立即返回,Android系統調用service的onStartCommand()方法。如果service還沒有運行,系統會先調用onCreate()方法,然後調用onStartCommand()。

 如果這個service沒有提供綁定,這個intent是應用程序組件和service之間溝通的唯一模式。然而如果你想service返回結果,啓動service的客戶端可以爲broadcast(用getBroadcast())創建一個PendingIntent並將其放在啓動service的Intent中傳遞給service。這時service可以使用broadcast來傳遞結果。

 多個start service的請求將導致多次service的相應onStartCommand()的調用。然而,只需要一個請求來stop service(使用stopSelf()或stopService())。

Stop一個service

 一個被啓動的service必須自己管理它的生命週期。換句話說,系統不會stop或者destory service,除非必須回收系統內存。所以service必須通過調用stopSelf()停止自己或讓其他組件調用stopService()來stop它。

 一旦使用stopSelf()或stopService()提交了請求,系統會盡快destroy它。

 然而,如果你的service同時處理多個提交給onStartCommand()的請求,當你處理完一個start請求時,你不應該stop這個service,因爲你也許已經接收了一個新的start請求(在第一個請求結束時stop將會終止第二個請求)。爲了避免這個問題,你可以調用stopSelf(int)來確保你對service的stop請求總是基於最近的start請求。也就是說,當你調用stopSelf(int),你傳遞一個start請求的ID給對應的stop請求。然後如果service在你能夠調用stopSelf(int)之前接收到一個新的start請求,這時這個ID將不會匹配,service也將不會stop。

 Caution:重要的一點是:當你的應用程序的service完成工作後,爲了避免系統資源的浪費以及電池的消耗,應該將其stop。如

果需要,其他的組件可以通過調用stopService()來stop這個service。雖然你可以爲你的service綁定,但是如果它曾接收

到一個onStartCommand()調用,你必須親自stop這個service。


--------------------------------------------------------------------------------

創建一個Bound Service
 一個bound service是允許程序組件用bindService()綁定到它上面,來創建一個長期存在的聯繫(並通常不允許組件通調用startService()來start它)。

 當你想要與來自你的應用程序中的activity和其它的組件的service相互作用或者通過進程間通信(IPC)對其他程序公開一些應用程序的功能,你可以創建一個bound service。

 爲了創建一個bound service,你必須實現onBind()回調函數返回一個IBinder來定義與這個service通信的接口。其它的組件就可以通過調用bindServiceIO來檢索這個接口並在service中調用方法。這個service只爲綁定到它上的組件存在,所以當沒有組件綁定到service上時,系統就會destory它(不同於通過onStartCommand()啓動的service,你不需要自己stop這個service)。

 爲了創建一個bound service,你首先要做的是聲明客戶端如何與service通信的接口。在service和客戶端之間的接口必須是一個IBinder的實現,並且必須由你的service的onBind()回調函數返回。一旦客戶端獲得這個IBinder,它就可以通過接口與service通信。

 多個客戶端可以一次性綁定到一個service。當一個service完成了與service的聯繫,它調用unbindServie()來解除綁定。一旦沒有客戶端綁定到service上時,系統就會destory這個service。

 有很多方法實現bound service並且這些實現都比started service實現複雜,所以bound service的討論將在另一個單獨的文檔。

 


--------------------------------------------------------------------------------

發送一個通知給用戶
 一旦運行,service就可以通過Toast Notification或Status Bar Notification來通知事件的用戶。

 toast notification是一個信息,該信息出現在當前窗口的表面,顯示一會就會消失。而一個status bar notification爲含有信息的狀態欄提供了一個圖標,用戶通過選擇來執行一個action(比如啓動一個activity)。

 通常在一些後臺工作完成後(比如文件下載完成),status bar 通知是通知用戶的最好的手法了。當用戶選擇了展開的視圖的通知時,這個通知可以啓動一個activity(比如顯示下載好的文件)。

 


--------------------------------------------------------------------------------

在前臺運行一個Service 
 前臺service是用戶需要知道並且在系統缺乏內存時不作爲候選的service。前臺service必須提供一個爲status bar使用的notification(通知)。該通知被置於”Ongoing”標題下,這意味着這個通知不能被解除,除非這個service stop或從前臺移除。

 比如說,一個音樂播放器利用一個可以設置爲前臺運行的service播放音樂,因爲用戶需要確定自己的操作。status bar上的通知或許指明當前播放的歌曲並允許用戶啓動一個activity來與音樂播放器交互。

 爲了要求你的service運行在前臺,可以調用startForeground()。這個方法有兩個參數:一個整數獨一無二的標識通知,一個爲status bar準備的Notification。比如說:

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),   
                                    System.currentTimeMillis());   
Intent notificationIntent = new Intent(this, ExampleActivity.class);   
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);   
notification.setLatestEventInfo(this, getText(R.string.notification_title),   
                     getText(R.string.notification_message), pendingIntent);   
startForeground(ONGOING_NOTIFICATION, notification);  
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
               System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
            getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION, notification);
 

 爲了將service從前臺移除,可以調用stopForeground()。這個方法有一個boolean參數來指明是否同樣移除status bar通知。這個方法不會stop這個service。然而如果你在service運行在前臺時stop了它,這個通知同樣會被移除。

 Note :startForeground()和stopForeground()方法是在Android2.0(API Level5)引入的。爲了能在之前的版本運行前臺service,你必須使用setForeground()方法。

 


--------------------------------------------------------------------------------

管理Service的生命週期
Service的生命週期比起activity要簡單。然而,密切注意你的service如何創建和銷燬將更爲重要,因爲一個service可以在用戶不知的情況下在後臺運行。

Service的生命週期—從創建到銷燬—可以遵循兩個途徑:

started service 
 當其他組件調用startService()時創建這個service。然後這個service無限期的運行並必須調用stopSelf() stop自己。別的組件也可以通過調用stopService()來stop這個service。當service被stop,系統就會destroy它。

bound service 
 當另一個組件(客戶端)調用bindService()時,service被創建。然後客戶端通過一個IBinder接口與service通信。這

個客戶端可以通過調用unbindService()關閉通信。多個客戶端可以綁定到service,當所有的客戶端解除綁定後,系統會destroy這個service。(這個service不需要自己stop)

 這兩個途徑並不是完全獨立的。也就是說,你可以綁定到一個已由startService()啓動的service。比如說,一個後臺的音樂service已經通過startService() 啓動,並傳遞一個Intent來指明要播放的音樂。之後,或許用戶想對播放器執行一些控制或者獲得當前播放的音樂的一些信息,可以通過調用bindService()來將activity綁定到service。在這種情況下,stopService()或stopSelf()在客戶端解除綁定前不能stop這個service。

實現生命週期回調函數:

 如同一個activity,service也有生命週期函數,你可以實現它們來監聽service狀態的變化並在合適的時候執行工作。下面的框架service展示了每個生命週期函數:

view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
public class ExampleService extends Service {   
    int mStartMode;       // 指明service被kill時如何反應   
    IBinder mBinder;      // 爲綁定的客戶端使用的接口   
    boolean mAllowRebind; // 指明onRebind是否可用    
    @Override  
    public void onCreate() {   
        // The service is being created   
    }   
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {   
        // The service is starting, due to a call to startService()   
        return mStartMode;   
    }   
    @Override  
    public IBinder onBind(Intent intent) {   
        // A client is binding to the service with bindService()   
        return mBinder;   
    }   
    @Override  
    public boolean onUnbind(Intent intent) {   
        // All clients have unbound with unbindService()   
        return mAllowRebind;   
    }   
    @Override  
    public void onRebind(Intent intent) {   
        // A client is binding to the service with bindService(),   
        // after onUnbind() has already been called   
    }   
    @Override  
    public void onDestroy() {   
        // The service is no longer used and is being destroyed   
    }   
}  
public class ExampleService extends Service {
    int mStartMode;       // 指明service被kill時如何反應
    IBinder mBinder;      // 爲綁定的客戶端使用的接口
    boolean mAllowRebind; // 指明onRebind是否可用 
    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}
 

 Note:不同於activity的生命週期函數,你不需要調用這些回調函數的超類實現。

通過實現這些方法,你可以監聽service生命週期的兩個嵌套的循環:

 service的entire lifetime發生在onCreate()被調用和onDestroy()返回之間。如同activity,一個service在onCreate()中做初始化工作,在onDestroy()中釋放所有剩餘的資源。比如說,一個音樂重放service可以在onCreate()中音樂播放的地方創建一個線程,然後在onDestroy()中stop這個線程。 
 無論是使用startService()還是binfService()創建service,onCreate()和onDestroy()函數都會被調用。

 

 service的active lifetime開始於onStartCommand()或onBind()的調用。每個方法都獲得一個傳遞給startService()或bindService()的Intent。 
 如果service是started,service的生命週期隨着activity的生命週期的結束而結束(即使在onStartCommand()返回後這個service仍然活躍)。如果這個service是bound,service的聲明週期在onUnbind()返回時結束。

 Note:雖然一個started service通過調用stopSelf()或stopService()來stop,卻沒有service各自的回調函數(沒有onStop()回調函數)。所以,除非這個service綁定了一個客戶端,否則在service 被stop的時候,系統就會銷燬它。

 

下圖顯示了service的特有的回調函數。雖然本圖將由startService()創建和bindService()創建的service分開來說,請記住任何service,無論其如何被創建,都可以允許客戶端來綁定它。所以,一個由onStartCommand()啓動的service仍可以接收一個onBind()的調用。

 

使用service還是使用一個線程:

 一個service是即使用戶沒有與你的應用程序交互也可以運行在後天的組件。然而你只有在需要的時候才應創建一個service。

如果在主線程外執行工作,但是只是在用戶與應用程序交互時執行,你應該創建一個新的線程而不是service。比如說,如果你想播放音樂,但是只有在你的activity運行時播放,你應該在onCreate()創建一個線程,在onStart()啓動運行,並在onStop()結束它的運行。

 請記住,如果你確實要使用一個service,它默認情況下在你的主線程運行,所以如果這個service執行密集性或者中斷性工作,你應該創建一個新的線程來供這個service使用。

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