Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發文檔翻譯之-Services

Android開發文檔翻譯之-Services

編輯:關於Android編程

Service是一種能長期在後台運行同時不需要與用戶進行交互的應用組件。其他組件可以開啟service,開啟後service可以自行運行及時用戶已經切換到其他的應用。此外,組件可以與service進行綁定來進行交互,及時是跨進程的交互(Android的IPC機制)。網絡操作、播放音樂、執行文件IO操作或是與內容提供者進行交互,這些操作都可以通過service在後台進行。

Service的兩種形式:

Started
通過調用startService(),你可以啟動一個service。一旦被啟動,service可以獨立的運行在後台,即使啟動的組件被銷毀。通常,被啟動的service用來執行一個單一的操作,並且沒有返回值。例如,下載網絡上的一個文件。當操作執行完畢後,service應當自行結束。

Bound
通過調用bindService(),你可以綁定一個service。一個被綁定的service一般會提供一個接口用來與組件進行交互、發送請求、獲取結果、甚至進行進程間的交互(IPC)。被綁定的service的生命周期和其綁定的組件相同。盡管多個組件可以同時綁定一個service,但是但所有這些組件進行解綁後,service會被銷毀。

雖然文檔中一般會對兩種形式的service分開介紹,但是你可以同時開啟和綁定service。只需要同時覆寫兩個回調-onStartCommand和onBind即可。
無論是用哪種方式啟動service(或是兩者都用),你都可以使用Intent來操作service,就想操作Activity一樣。然而,如果你不想讓其他應用使用你的service,你可以在manifest文件中將service申明為私有的,具體請看Service在清單文件中的申明

基礎介紹
想要使用service,你需要繼承Service類或其子類。你需要覆寫一些回調方法同時在這些方法中進行一些關鍵操作。一下是一些較為重要的生命周期回調回調:

onStartCommand()
系統會在你調用了startService後調用該函數。一旦該方法執行,service會被啟動並獨立運行在後台。如果你實現了該方法,你必須在合適的時機調用stopSelf()或者stopService()來停止service。(如果你僅提供綁定接口,你可以不實現該方法)

onBind()
當有其他組件通過bindService()綁定service後,系統會調用onBind()函數。你需要在該方法中提供一個實現了IBinder接口的類供給client使用。該方法必須要覆寫,如果你不希望你的service提供綁定功能,你可以直接返回null。

Android系統會在內存較低時強制停止service;如果service被綁定在一個擁有焦點的activity上時,其被kill的風險會降低;如果一個service被申明為前台service,那麼它幾乎不會被kill。否者的話,如果service被長時間開啟,那麼隨著時間的推移,service在系統中的優先級就會越低,被kill的風險就會越高。如果你的service被啟動了,那麼你就應該考慮到其被系統kill的情況。如果系統kill了一個service,那麼在資源寬松的情況下,系統會重啟它(這個需要根據你在onStartCommand()的返回值決定重啟的策略)。

Service在清單文件中的申明
和activity一樣,你需要在清單文件中申明service。


  ...
  
      
      ...
  

在service節點中可以申明一些其他的屬性。這些屬性都是可選的。只有android:name這一屬性是必須的——該屬性用來描述一個唯一的service類名,你應該確保不去修改該類名。
為了確保你的應用的安全性,應該使用顯式意圖來啟動或者綁定service,並且不在service中申明intent-filters。
此外,你可以通過設置android:exported屬性為false來確保你的service僅可以在你自己的應用中被使用。這可以有效得阻止其他應用使用你的service,即使通過顯式意圖也不可以。

以啟動方式創建service
可以通過startService()來啟動service,你可以監聽到onStartCommand()回調。
當一個service被啟動後,它將擁有獨立的生命周期並且獨立的運行在後台,即使開啟它的組件被銷毀。這種情況下,你需要在合適的時機調用stopSelf()來結束它或者通過調用stopServie()來結束它。
調用startService()時傳遞的Intent會在onStartCommand()回調時接收到。

注意:service會默認運行在申明service的那個應用進程中,並且會運行在主線程中。所以如果你的service在執行一些密集或阻塞的操作,那麼可能會造成ANR現象。為了避免這種情況,你需要開啟一個新的線程。

一般來說,你可以通過繼承IntentService類來加速你的開發。

繼承IntentService類
由於大部分的service都不需要處理並發請求,因此你可以通過繼承IntentService類來加速你的開發。

IntentService有以下特性:

1.創建了一個工作線程來執行由onStartCommand()中傳遞的intent,該線程是和主線程分離的。
2.創建了一個工作隊列用來依次執行intent,因此你不需要考慮多線程問題。
3.當所有任務執行結束後會自動的調用stopSelf()。
4.提供了onBind()的默認實現(return null)
5.提供了onStartCommand()的默認實現,發送任務到任務隊列中並且回調onHandleIntent()

上述這些特性使得你只需要實現onHandleIntent()就可以完成client端的任務(你還需要提供一個簡單的構造函數)
以下是IntentService的一個實現:

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.
      try {
          Thread.sleep(5000);
      } catch (InterruptedException e) {
          // Restore interrupt status.
          Thread.currentThread().interrupt();
      }
  }
}

對比一下,如果你繼承自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.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // 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好啊。
然而,如果你希望實現並發操作,即不等上一個請求執行完畢就進行下一個請求的話,那麼直接繼承service是有必要的。

注意到onStartCommand()方法必須返回一個整型變量。這個整型變量用來指定當系統殺死service後應當如何返回。以下是各個返回值:

START_NOT_STICKY
系統殺死service後不會重新創建該service,除非需要傳遞pending intents。適用於當你的程序可以簡單的重啟未完成任務的service。

START_STICKY
如果系統殺死了service,那麼之後會重啟該service並且調用onStartCommand(),但是不會重新發送上一個intent,而是返回一個null的intent(除非是一個pending intents。)這種模式很適合音樂播放器這種不需要執行commands,但是需要獨立運行並且等待任務的service。

START_REDELIVER_INTENT
如果系統殺死了service,那麼之後會重啟該service並且掉哦那個onStartCommand(),並且會傳遞上一個intent。這中模式適合那些需要立即返回的service,例如下載文件。

以綁定方式啟動service
詳見Android開發文檔翻譯之-Bound Services

給用戶發送通知
一旦service運行,你可以通過Toast Notifications或者Status Bar Notifications來告知用戶某些事件。
Toast Notifications是一種短時間內出現在當前窗口表面的一條消息。Status Bar Notifications是一種提供了圖標和消息的通知欄,用戶可以通過點擊來執行某個動作(例如開啟一個activity)

前台Service
前台Service通常用來執行一些需要用戶意識到正在執行的一些操作,因此系統在低內存狀態時也不會kill掉該service。前台Service需要在狀態欄上提供一個通知,該通知不會消失,直到service被停止或者從前台移除。
例如,音樂播放器Service應該是被設置為運行在前台的service,因為用戶應該一直意識到這個操作。狀態欄應該顯示當前正在播放的歌曲,並且當前點擊後應該跳轉到能和用戶進行交互的activity。
通過調用startForeground()函數可以讓你的service運行在前台。使用示例如下:

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

管理Service的生命周期
Service的生命周期相對Activity要簡單的多。但是卻更需要你注意,因為通常service是運行在後台的。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved