Develop系列-API Guides-應用組件-Services,-api-services

來源:互聯網
上載者:User

Develop系列-API Guides-應用組件-Services,-api-services
Services

Services:可在後台長時間運行,無UI介面。

Started:

   

Services通過其他組件調用startService啟動,能在後台一直運行,即使啟動它的組件已經銷毀。一般這種服務執行特定的操作而且沒有傳回值,比如通過網路下載或上傳一個檔案,一旦操作結束,服務需要停止自己。

Bound:

   

Service通過其他組件調用bindService綁定,提供一個CS架構的介面允許其他組件與Service互動、發訊息、擷取傳回值、甚至跨進程通訊。bound service與綁定它的組件共存亡,多個組件可以綁定一個服務,當這個服務所有綁定它的組件都解除綁定後,服務會被銷毀。

Caution:Service在宿主進程的主線程運行,也就是說Service不會建立自己的線程,也不會運行在另一個進程(除非你指定)。這就意味著,如果Service執行一些高CPU負載或阻塞介面操作的任務時,你需要建立新的線程來運行它,以降低ANR的風險。

(使用service還是thread?如果你只是需要在與使用者互動時,在主線程之外執行額外的任務,那麼你需要建立一個新線程而不是Service。比如在activity在前台顯示的時候播放音樂,你需要在onCreate裡面建立線程,在onStart執行線程,在onStop裡停止線程,當然也可以使用AsyncTask或者HandleThread來替代線程類。)

基礎

建立Service的子類,覆寫Service生命週期中的關鍵回呼函數,如果有必要,提供綁定Service的機制。最重要的回呼函數如下:

onStartCommand

   

系統在其他組件調用startService啟動Service時執行,之後,Service一直在後台執行。如果你實現了這個方法,那麼你有責任在Service完成其工作時通過stopSelf或stopService來停止Service。(如果只是提供綁定Service,可以不用實現這個方法)

onBind

   

系統在其他組件調用bindService綁定Service時執行,在這個方法的實現中,你需要返回一個IBider介面用於clients與service互動。如果你不需要綁定,可以直接返回null

onCreate

   

Service第一次建立時執行,在onStartCommand和onBind之前,用於執行一次性需要初始化好的資料。

onDestroy

   

service銷毀時執行,用於清理資源,類似線程、註冊監聽器,receiver等。

 

系統會在低記憶體時強制停止service。如果service綁定在一個有使用者焦點的activity,那麼它很少會被銷毀;如果服務定義為在前台啟動並執行,那麼它永遠不會被銷毀。

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

android:name是唯一必填的屬性,其他可以選填。一旦你的應用發布出去了,那麼android:name永遠不要再變。

為了安全性,請使用顯式Intent啟動或綁定服務,而不是定義filiters。如果確實允許多個服務來響應,那麼請務必在Intent中通過setPackage來指定報名,以降低目標服務匹配出意外值得機率。

設定android:exported為false,可以避免其他應用啟動這個服務。

建立service

Service

  

所有服務的基類,如果你擴充這個類,那麼你可能需要建立一個新的線程,因為這個服務室在app的主線程中執行,有可能會降低activity的流暢度

IntentService

  

Service 的子類,通過背景工作執行緒來處理所有請求,每次處理一個。如果你的service不需要同時處理多個請求,IntentService是最佳的選擇。

擴充IntentService

因為大部分服務不需要同時處理多個請求(實際上是個多線程情境),IntentService是最好的推薦

IntentService工作流程如下:

  • 建立一個預設的新背景工作執行緒來執行所有分發給onStartCommand的intents
  • 建立一個工作隊列來依次傳遞intent去執行onHandleIntent具體實現,所以不需要考慮多線程情境
  • 所有請求執行完之後,自動銷毀,你不需要執行stopSelf
  • 提供預設的onBind實現:直接返回null
  • 提供onStartCommand預設實現:發送intent給背景工作執行緒執行onHandleIntent實現

實際上,你需要做的就是實現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才能處理背景工作執行緒的生命週期。onHandleIntent和onBind是例外。

擴充Service

如果服務需要支援多線程(而不是通過工作隊列來一一處理),那麼你要擴充Service來處理每一個intent。

作為對比,如下代碼和上面代碼功能一樣。

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();  }}

這個只是類比IntentService處理,有必要的話,你可以為每一個請求建立一個線程。

 

onStartCommand必須返回一個整型,這個值用來描述系統如何處理這個服務,當它被異常銷毀時。

START_NOT_STICKY

  

如果服務執行完onStartCommand後被異常銷毀,不需要重新建立服務,除非還有未處理的intents。避免服務被不必要地啟動,你的應用能夠很容易地重新啟動未完成的工作,選擇這個。

START_STICKY

  

如果服務執行完onStartCommand後被異常銷毀,重新建立服務並執行onStartCommand,但是不會使用發給這個服務的最後一個intent,而是通過一個null intent來執行onStartCommand,除非還有未處理的intents。這種情況比較適合不執行命令,一直在後台運行或者等待任務的媒體播放。

START_REDELIVER_INTENT

  

如果服務執行完onStartCommand後被異常銷毀,重新建立服務,用發給這個服務的最後一個intent調用onStartCommand,其他未處理的intents依次分發。這種情況適合執行的任務需要理解恢複的情境,比如下載檔案。

啟動服務

startService –> onStartCommand

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

startService方法立即返回。

如果service不能綁定,只能通過startService啟動,而且需要發送傳回值時,可以通過建立帶延遲廣播的PendingIntent(用getBroadcast)來啟動服務,服務能用裡面的廣播來分髮結果。

停止服務

如果服務同步地處理多個請求,那麼不能在處理完一個請求直接銷毀,有可能其他的請求剛發過來或者還在處理中。為了避免這種情況,你可以通過stopSelf(int)來確保關閉的服務就是剛處理完請求的,而不是其他正在處理的服務,整型參數唯一識別服務執行個體。

建立綁定服務

詳見下一章節

發送Notifications給使用者

服務一旦運行,可以通過Toast Notifications和Status Bar Notifications提醒使用者。

在前台運行服務

在前台啟動並執行服務必須提供一個狀態列的notification,來呈現運行狀態,除非服務被停止或者移除,否則notification不會消失。

比如:播放音樂,在狀態列有個notification來告訴使用者當前播放的歌曲,提供使用者進入音樂播放器的入口

服務需要在前台運行,需要調用startForground,第一個參數是notification的唯一標示(不能為0),第一參數就是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_ID, notification);

停止在前台運行,可以調用stopForeground。

實現生命週期回調
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    }}

Note:不需要執行父類的實現。

 

完整的生命週期:onCreate —> onDestroy

活動的生命週期:onStartCommand/onBind —> onDestroy/onUnbind




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.