天天看點

【android官方文檔節選】ServiceServices基礎在manifest聲明建立一個started service     繼承自IntentService類繼承自Service類建立一個Bound Service     運作一個Service在前端程序 管理Service的生命周期

如轉載請注明出處http://blog.csdn.net/ethanchiu/article/details/19413151

Services

一個服務有兩種形式

1.Started

     一旦一個元件調用了startService(),service就是“started”狀态,一旦開始,即使啟動它的元件銷毀了,一個service可以無限期的運作在背景。通常一個啟動的service執行一個操作,并且不會傳回結果給喚起者。比如,可以通過網絡下載下傳或者上傳一個檔案。當操作完成,服務應該停止自己。

2.Bound

     一旦一個元件調用了bindService(),service就是“bound”狀态。一個bound service提供一個clientserver接口,這個接口允許元件和service互動,發送請求,獲得結果,甚至程序間通信。一個bound service隻有在和他綁定的時候才會運作。多個元件可以一次綁定到service,當所有的元件都解綁的時候,service就銷毀了。

     雖然文檔是分開讨論者兩種service的,但是serivce可以同時工作在這兩種方式上—即可以啟動,又可以綁定。隻要看是否實作了一對回調方法:onStartCommand()和onBind()。

警告:一個service運作在主線程中--service不會建立一個自己的線程,不會運作在另一個程序中(除非指定了)。這就意味了,如果service執行cpu敏感的工作或者阻塞操作(比如MP3播放或者網絡工作),需要在service中建立一個線程去做那些工作。通過一個單獨的線程,可以減少ANR的風險,主線程可以保持隻做使用者互動先關的任務。

基礎

    onStartCommand()

     當其他元件比如activity通過調用startService()請求的service開始了,這個方法将會被調用。一旦這個方法執行,service就會啟動,并且一直運作在背景。如果你實作這個方法,service的任務完成的時候,就有責任停止這個服務,通過調用stopSelf()或者stopService()。(如果隻是想提供綁定,就沒必要實作這個方法)。

      onBind()

     當另一個元件通過調用bindService()想綁定這個service的時候,系統調用這個方法。在這個方法的實作中,通過傳回一個IBinder提供一個使用者和service互動的接口。如果不想綁定,傳回null。

     onCreate()

     service第一次建立的時候,系統調用這個方法,來執行一次安裝程序。如果service已經運作,這個方法不會調用。

     onDestroy()

     當service不再使用銷毀的時候調用。service應該實作這個方法去清除一些資源比如線程,注冊的監聽器,接受器,等等。

     通過startService()啟動一個元件(會調用onStartCommand),它會一直保持運作,直到自己調用stopSelf()或者另一個元件調用stopService()。

     通過調用bindService()建立一個service(onStartCommand不會回調),service隻會在元件綁定的時候運作。如果所有元件都解綁了,這個service就會銷毀。

     當記憶體低的時候,系統會強制停止一個服務,來恢複系統資源給有使用者焦點的Activity。如果一個Activity獲得焦點并且綁定了service,那麼這個service被殺死的可能性比較小,并且如果service被聲明前端運作,那麼這個service幾乎不會被殺死。除此之外,如果service開始了并且長時間運作,那麼系統會降低它的背景任務優先級并且很可能被系統殺死--如果service啟動了,你就該設計一個讓系統重新啟動它的機制。如果系統殺死了service,一旦資源可用之後應該重新開機它。更多關于系統殺死service,看Processes and Threading部分。

在manifest聲明

     如果要想隻在自己的app中使用這個service,需要加入android:exported屬性,并且設定為false。這個可以有效停止其他app啟動這個service,甚至使用了隐式intent也不可以。

建立一個started service     

 有兩種類可以實作一個started service

Service

     是所有services的基類。當內建這個類,最重要的是建立一個新的線程去做所有的service任務,因為這個service使用了程式的主線程。

IntentService

     這是Service的子類,它使用一個工作線程處理所有的開始請求任務。如果不需要service同時處理多個請求,這是最好的選擇。實作 onHandleIntent(),可以接收到每個請求傳回的intent。

繼承自IntentService類

     因為大多數started services 不需要同是處理多個請求(就是危險的多線程方案),IntentService是最好的選擇。

     IntentService的功能:

建立一個預設的線程去處理所有通過onStartCommand()傳過來的intents。

建立一個工作隊列,在 onHandleIntent()中一時間傳過來一個,隊列處理,是以不要擔心多線程。

所有請求處理完成之後,自己停止服務,不需要調用stopSelf()。

提供傳回null的onBind() 的預設實作

提供onStartCommand()的預設實作,它發送intent到工作隊列。

     是以隻要實作了onHandleIntent()去做需要做的任務就行了。

public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}
           

     如果想重寫onCreate(),onStartCommand(),或者onDestroy(),確定調用了父類實作,這樣IntentService可以在工作線程中處理任務。

     比如,onStartCommand()必須傳回預設實作(這就是intent傳遞到onHandleIntent()的原因):

@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類去處理每一個intent。

     以下是實作和IntentService一樣功能,service對應的代碼。

public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service.  Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block.  We also make it
    // background priority so CPU-intensive work will not disrupt our 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();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      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();
  }
}
           

     在onStartCommand()方法中必須傳回一個整型資料。這個整型描述了當系統殺掉它的情況下,系統那個将如何繼續這個service。這個傳回的整型如下:

開始一個Service      

     如果想service發送一個結果傳回,啟動service的元件可以為broadcast(使用getBroadcast())建立一個PedingIntent并且在Intent中将它傳遞給service。service可以使用broadcast傳遞一個結果。

停止一個Service

     在service中停止服務使用stopSelf(),在其他元件中停止服務調用stopService()。

     如果service在onstartcommand處理多個請求,不應該停止服務當處理完一個請求的時候,因為你可能接收到了一個新的請求(在一個請求完畢之後,停止操作可能終止了第二個請求)。為了避免這種情況,可以使用stopSelf(int)來確定停止的請求是之前發起的對應請求。

建立一個Bound Service     

一個bound Service是允許元件為了建立一個長時間連接配接的的服務。

     這個service的存在是服務于和它綁定的元件的,是以當沒有元件綁定它的時候,這個service就是銷毀。

     建立一個bound service,第一件事就是定義一個接口,這個接口決定元件如何和service互動。而這個接口需要通過IBinder實作,并且這個接口通過onBind()傳回。

     一次有多個元件綁定到service。元件和service互動完,需要調用unbindService()去解綁。

運作一個Service在前端程序

     一個前端程序的service是使用者特别關心的,是以當記憶體低的時候,不希望系統殺死他。一個前端service必須提供一個通知給狀态欄,在“前進欄”的下面,意味着,這個通知不能消失,直到service停止或者從前端狀态移除。

     比如,一個音樂播放器,播放音樂的的服務應該在前端程序,因為使用者明确關心這個操作。通知欄可以顯示目前的歌曲并且允許使用者登入到Activity操作播放器。

     運作在前端的操作是調用startForeground()。這個方法帶有兩個參數:一個是整型對應通知,還有一個是狀态欄的通知。     比如:

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_ID, notification);
           

警告:startForeground的整型ID必須為0

     調用stopForeground()将service從前端程序移除。有個boolean變量,指明這條狀态是否也移除。這個方法不會停止service。然而,如果當在前端程序運作的時候停止了service,這個通知也會移除。

 管理Service的生命周期

     service的生命周期—從何時建立到何時銷毀--遵循以下兩種不同的途徑。

started service

     調用startService()建立service。service一直 運作在背景,直到調用stopSelf()。或者其他元件調用stopService()。service停止了,系統會銷毀他。

bound service

     調用bindService()建立service。所有綁定這個service的元件都解綁了,service就銷毀。

     這兩種方式不是完全獨立的。可以通過startService啟動。比如,一個背景音樂service通過startService啟動。後來,使用者想通過測試這個播放器或者獲得歌的資訊,一個Activity和這個service通過bindService()綁定。這種情況下,stopService()後者stopSelf()不會停止service,知道所有的元件都解綁了。

實作生命周期的回調

     下面是service生命周期回調的骨架。

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @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
    }
}
           
【android官方文檔節選】ServiceServices基礎在manifest聲明建立一個started service     繼承自IntentService類繼承自Service類建立一個Bound Service     運作一個Service在前端程式 管理Service的生命周期

通過實作這些方法,可以監測兩個内部循環的service生命周期:

entire lifetime

     entire lifetime發生在onCreate()和onDestroy()之間。     

active lifetime

     active lifetime開始于onStartCommand()或者onBind()。每一個方法處理的Intent被傳遞到startService()或者bindService()。

     如果service開始了,active lifetime結局了,那麼entire lifetime也會結束。(onStartCommand()傳回後,service任然活動的)。如果service解綁了,當onUnbind()傳回,active lifetime就結束了。

圖上闡明了service的回調的特征。雖然圖将startService和bindService差別開來,記住,任何service它是怎麼啟動的,元件都可以綁定它。是以一個service以onStartCommand啟動(通過調用startService())任然可以接受onBind()(當一個元件調用了bindService)。