Android -- Service基礎簡介

Android -- Service基礎簡介


PS:來源 Service


Service 是一個可以在後臺執行長時間運行操作而不提供用戶界面的應用組件。服務可由其他應用組件啓動,而且即使用戶切換到其他應用,服務仍將在後臺繼續運行。 此外,組件可以綁定到服務,以與之進行交互,甚至是執行進程間通信 (IPC)。 例如,服務可以處理網絡事務、播放音樂,執行文件 I/O 或與內容提供程序交互,而所有這一切均可在後臺進行。

服務基本上分爲兩種形式:

啓動


當應用組件(如 Activity)通過調用 startService() 啓動服務時,服務即處於“啓動”狀態。一旦啓動,服務即可在後臺無限期運行,即使啓動服務的組件已被銷燬也不受影響。 已啓動的服務通常是執行單一操作,而且不會將結果返回給調用方。例如,它可能通過網絡下載或上傳文件。 操作完成後,服務會自行停止運行。


綁定


當應用組件通過調用 bindService() 綁定到服務時,服務即處於“綁定”狀態。綁定服務提供了一個客戶端-服務器接口,允許組件與服務進行交互、發送請求、獲取結果,甚至是利用進程間通信 (IPC) 跨進程執行這些操作。 僅當與另一個應用組件綁定時,綁定服務纔會運行。 多個組件可以同時綁定到該服務,但全部取消綁定後,該服務即會被銷燬。
雖然本文檔是分開概括討論這兩種服務,但是您的服務可以同時以這兩種方式運行,也就是說,它既可以是啓動服務(以無限期運行),也允許綁定。問題只是在於您是否實現了一組回調方法:onStartCommand()(允許組件啓動服務)和 onBind()(允許綁定服務)。

無論應用是處於啓動狀態還是綁定狀態,抑或處於啓動並且綁定狀態,任何應用組件均可像使用 Activity 那樣通過調用 Intent 來使用服務(即使此服務來自另一應用)。 不過,您可以通過清單文件將服務聲明爲私有服務,並阻止其他應用訪問。 使用清單文件聲明服務部分將對此做更詳盡的闡述。

注意:服務在其託管進程的主線程中運行,它既不創建自己的線程,也不在單獨的進程中運行(除非另行指定)。 這意味着,如果服務將執行任何 CPU 密集型工作或阻止性操作(例如 MP3 播放或聯網),則應在服務內創建新線程來完成這項工作。通過使用單獨的線程,可以降低發生“應用無響應”(ANR) 錯誤的風險,而應用的主線程仍可繼續專注於運行用戶與 Activity 之間的交互。

基礎知識


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

onStartCommand()


當另一個組件(如 Activity)通過調用 startService() 請求啓動服務時,系統將調用此方法。一旦執行此方法,服務即會啓動並可在後臺無限期運行。 如果您實現此方法,則在服務工作完成後,需要由您通過調用 stopSelf() 或 stopService() 來停止服務。(如果您只想提供綁定,則無需實現此方法。)


onBind()


當另一個組件想通過調用 bindService() 與服務綁定(例如執行 RPC)時,系統將調用此方法。在此方法的實現中,您必須通過返回 IBinder 提供一個接口,供客戶端用來與服務進行通信。請務必實現此方法,但如果您並不希望允許綁定,則應返回 null。


onCreate()


首次創建服務時,系統將調用此方法來執行一次性設置程序(在調用 onStartCommand() 或 onBind() 之前)。如果服務已在運行,則不會調用此方法。


onDestroy()


當服務不再使用且將被銷燬時,系統將調用此方法。服務應該實現此方法來清理所有資源,如線程、註冊的偵聽器、接收器等。 這是服務接收的最後一個調用。
如果組件通過調用 startService() 啓動服務(這會導致對 onStartCommand() 的調用),則服務將一直運行,直到服務使用 stopSelf() 自行停止運行,或由其他組件通過調用 stopService() 停止它爲止。

如果組件是通過調用 bindService() 來創建服務(且未調用 onStartCommand(),則服務只會在該組件與其綁定時運行。一旦該服務與所有客戶端之間的綁定全部取消,系統便會銷燬它。

僅當內存過低且必須回收系統資源以供具有用戶焦點的 Activity 使用時,Android 系統纔會強制停止服務。如果將服務綁定到具有用戶焦點的 Activity,則它不太可能會終止;如果將服務聲明爲在前臺運行(稍後討論),則它幾乎永遠不會終止。或者,如果服務已啓動並要長時間運行,則系統會隨着時間的推移降低服務在後臺任務列表中的位置,而服務也將隨之變得非常容易被終止;如果服務是啓動服務,則您必須將其設計爲能夠妥善處理系統對它的重啓。 如果系統終止服務,那麼一旦資源變得再次可用,系統便會重啓服務(不過這還取決於從 onStartCommand() 返回的值,本文稍後會對此加以討論)。

在下文中,您將瞭解如何創建各類服務以及如何從其他應用組件使用服務。


您應使用服務還是線程?


簡單地說,服務是一種即使用戶未與應用交互也可在後臺運行的組件。 因此,您應僅在必要時才創建服務。

如需在主線程外部執行工作,不過只是在用戶正在與應用交互時纔有此需要,則應創建新線程而非服務。 例如,如果您只是想在 Activity 運行的同時播放一些音樂,則可在 onCreate() 中創建線程,在 onStart() 中啓動線程,然後在 onStop() 中停止線程。您還可以考慮使用 AsyncTask 或 HandlerThread,而非傳統的 Thread 類。如需瞭解有關線程的詳細信息,請參閱進程和線程文檔。

請記住,如果您確實要使用服務,則默認情況下,它仍會在應用的主線程中運行,因此,如果服務執行的是密集型或阻止性操作,則您仍應


使用清單文件聲明服務


如同 Activity(以及其他組件)一樣,您必須在應用的清單文件中聲明所有服務。

要聲明服務,請添加 <service> 元素作爲 <application> 元素的子元素。例如:

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>
您還可將其他屬性包括在 <service> 元素中,以定義一些特性,如啓動服務及其運行所在進程所需的權限。android:name 屬性是唯一必需的屬性,用於指定服務的類名。應用一旦發佈,即不應更改此類名,如若不然,可能會存在因依賴顯式 Intent 啓動或綁定服務而破壞代碼的風險(請閱讀博客文章Things That Cannot Change[不能更改的內容])。

爲了確保應用的安全性,請始終使用顯式 Intent 啓動或綁定 Service,且不要爲服務聲明 Intent 過濾器。 啓動哪個服務存在一定的不確定性,而如果對這種不確定性的考量非常有必要,則可爲服務提供 Intent 過濾器並從 Intent 中排除相應的組件名稱,但隨後必須使用 setPackage() 方法設置 Intent 的軟件包,這樣可以充分消除目標服務的不確定性。

此外,還可以通過添加 android:exported 屬性並將其設置爲 "false",確保服務僅適用於您的應用。這可以有效阻止其他應用啓動您的服務,即便在使用顯式 Intent 時也如此。

創建啓動服務


啓動服務由另一個組件通過調用 startService() 啓動,這會導致調用服務的 onStartCommand() 方法。

服務啓動之後,其生命週期即獨立於啓動它的組件,並且可以在後臺無限期地運行,即使啓動服務的組件已被銷燬也不受影響。 因此,服務應通過調用 stopSelf() 結束工作來自行停止運行,或者由另一個組件通過調用 stopService() 來停止它。

應用組件(如 Activity)可以通過調用 startService() 方法並傳遞 Intent 對象(指定服務幷包含待使用服務的所有數據)來啓動服務。服務通過 onStartCommand() 方法接收此 Intent。

例如,假設某 Activity 需要將一些數據保存到在線數據庫中。該 Activity 可以啓動一個協同服務,並通過向 startService() 傳遞一個 Intent,爲該服務提供要保存的數據。服務通過 onStartCommand() 接收 Intent,連接到互聯網並執行數據庫事務。事務完成之後,服務會自行停止運行並隨即被銷燬。

注意:默認情況下,服務與服務聲明所在的應用運行於同一進程,而且運行於該應用的主線程中。 因此,如果服務在用戶與來自同一應用的 Activity 進行交互時執行密集型或阻止性操作,則會降低 Activity 性能。 爲了避免影響應用性能,您應在服務內啓動新線程。

從傳統上講,您可以擴展兩個類來創建啓動服務:

Service


這是適用於所有服務的基類。擴展此類時,必須創建一個用於執行所有服務工作的新線程,因爲默認情況下,服務將使用應用的主線程,這會降低應用正在運行的所有 Activity 的性能。


IntentService


這是 Service 的子類,它使用工作線程逐一處理所有啓動請求。如果您不要求服務同時處理多個請求,這是最好的選擇。 您只需實現 onHandleIntent() 方法即可,該方法會接收每個啓動請求的 Intent,使您能夠執行後臺工作。
下文介紹如何使用其中任一個類來實現服務。

擴展 IntentService 類


由於大多數啓動服務都不必同時處理多個請求(實際上,這種多線程情況可能很危險),因此使用 IntentService 類實現服務也許是最好的選擇。

IntentService 執行以下操作:

  • 創建默認的工作線程,用於在應用的主線程外執行傳遞給 onStartCommand() 的所有 Intent。
  • 創建工作隊列,用於將 Intent 逐一傳遞給 onHandleIntent() 實現,這樣您就永遠不必擔心多線程問題。
  • 在處理完所有啓動請求後停止服務,因此您永遠不必調用 stopSelf()。
  • 提供 onBind() 的默認實現(返回 null)。
  • 提供 onStartCommand() 的默認實現,可將 Intent 依次發送到工作隊列和 onHandleIntent() 實現。
綜上所述,您只需實現 onHandleIntent() 來完成客戶端提供的工作即可。(不過,您還需要爲服務提供小型構造函數。)

以下是 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();
      }
  }
}
您只需要一個構造函數和一個 onHandleIntent() 實現即可。

如果您決定還重寫其他回調方法(如 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 基類時實現同類服務。該基類包含更多代碼,但如需同時處理多個啓動請求,則更適合使用該基類。

擴展服務類


正如上一部分中所述,使用 IntentService 顯著簡化了啓動服務的實現。但是,若要求服務執行多線程(而不是通過工作隊列處理啓動請求),則可擴展 Service 類來處理每個 Intent。

爲了便於比較,以下提供了 Service 類實現的代碼示例,該類執行的工作與上述使用 IntentService 的示例完全相同。也就是說,對於每個啓動請求,它均使用工作線程執行作業,且每次僅處理一個請求。
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 相比,這需要執行更多工作。

但是,因爲是由您自己處理對 onStartCommand() 的每個調用,因此可以同時執行多個請求。此示例並未這樣做,但如果您希望如此,則可爲每個請求創建一個新線程,然後立即運行這些線程(而不是等待上一個請求完成)。

請注意,onStartCommand() 方法必須返回整型數。整型數是一個值,用於描述系統應該如何在服務終止的情況下繼續運行服務(如上所述,IntentService 的默認實現將爲您處理這種情況,不過您可以對其進行修改)。從 onStartCommand() 返回的值必須是以下常量之一:

START_NOT_STICKY

如果系統在 onStartCommand() 返回後終止服務,則除非有掛起 Intent 要傳遞,否則系統不會重建服務。這是最安全的選項,可以避免在不必要時以及應用能夠輕鬆重啓所有未完成的作業時運行服務。

START_STICKY

如果系統在 onStartCommand() 返回後終止服務,則會重建服務並調用 onStartCommand(),但不會重新傳遞最後一個 Intent。相反,除非有掛起 Intent 要啓動服務(在這種情況下,將傳遞這些 Intent ),否則系統會通過空 Intent 調用 onStartCommand()。這適用於不執行命令、但無限期運行並等待作業的媒體播放器(或類似服務)。

START_REDELIVER_INTENT


如果系統在 onStartCommand() 返回後終止服務,則會重建服務,並通過傳遞給服務的最後一個 Intent 調用 onStartCommand()。任何掛起 Intent 均依次傳遞。這適用於主動執行應該立即恢復的作業(例如下載文件)的服務。

啓動服務


您可以通過將 Intent(指定要啓動的服務)傳遞給 startService(),從 Activity 或其他應用組件啓動服務。Android 系統調用服務的 onStartCommand() 方法,並向其傳遞 Intent。(切勿直接調用 onStartCommand()。)

例如,Activity 可以結合使用顯式 Intent 與 startService(),啓動上文中的示例服務 (HelloService):
Intent intent = new Intent(this, HelloService.class);
startService(intent);
startService() 方法將立即返回,且 Android 系統調用服務的 onStartCommand() 方法。如果服務尚未運行,則系統會先調用 onCreate(),然後再調用 onStartCommand()。

如果服務亦未提供綁定,則使用 startService() 傳遞的 Intent 是應用組件與服務之間唯一的通信模式。但是,如果您希望服務返回結果,則啓動服務的客戶端可以爲廣播創建一個 PendingIntent (使用 getBroadcast()),並通過啓動服務的 Intent 傳遞給服務。然後,服務就可以使用廣播傳遞結果。

多個服務啓動請求會導致多次對服務的 onStartCommand() 進行相應的調用。但是,要停止服務,只需一個服務停止請求(使用 stopSelf() 或 stopService())即可。

停止服務


啓動服務必須管理自己的生命週期。也就是說,除非系統必須回收內存資源,否則系統不會停止或銷燬服務,而且服務在 onStartCommand() 返回後會繼續運行。因此,服務必須通過調用 stopSelf() 自行停止運行,或者由另一個組件通過調用 stopService() 來停止它。

一旦請求使用 stopSelf() 或 stopService() 停止服務,系統就會盡快銷燬服務。

但是,如果服務同時處理多個 onStartCommand() 請求,則您不應在處理完一個啓動請求之後停止服務,因爲您可能已經收到了新的啓動請求(在第一個請求結束時停止服務會終止第二個請求)。爲了避免這一問題,您可以使用 stopSelf(int) 確保服務停止請求始終基於最近的啓動請求。也就說,在調用 stopSelf(int) 時,傳遞與停止請求的 ID 對應的啓動請求的 ID(傳遞給 onStartCommand() 的 startId)。然後,如果在您能夠調用 stopSelf(int) 之前服務收到了新的啓動請求,ID 就不匹配,服務也就不會停止。

注意:爲了避免浪費系統資源和消耗電池電量,應用必須在工作完成之後停止其服務。 如有必要,其他組件可以通過調用 stopService() 來停止服務。即使爲服務啓用了綁定,一旦服務收到對 onStartCommand() 的調用,您始終仍須親自停止服務。


創建綁定服務


綁定服務允許應用組件通過調用 bindService() 與其綁定,以便創建長期連接(通常不允許組件通過調用 startService() 來啓動它)。

如需與 Activity 和其他應用組件中的服務進行交互,或者需要通過進程間通信 (IPC) 向其他應用公開某些應用功能,則應創建綁定服務。

要創建綁定服務,必須實現 onBind() 回調方法以返回 IBinder,用於定義與服務通信的接口。然後,其他應用組件可以調用 bindService() 來檢索該接口,並開始對服務調用方法。服務只用於與其綁定的應用組件,因此如果沒有組件綁定到服務,則系統會銷燬服務(您不必按通過 onStartCommand() 啓動的服務那樣來停止綁定服務)。

要創建綁定服務,首先必須定義指定客戶端如何與服務通信的接口。 服務與客戶端之間的這個接口必須是 IBinder 的實現,並且服務必須從 onBind() 回調方法返回它。一旦客戶端收到 IBinder,即可開始通過該接口與服務進行交互。

多個客戶端可以同時綁定到服務。客戶端完成與服務的交互後,會調用 unbindService() 取消綁定。一旦沒有客戶端綁定到該服務,系統就會銷燬它。


在前臺運行服務


前臺服務被認爲是用戶主動意識到的一種服務,因此在內存不足時,系統也不會考慮將其終止。 前臺服務必須爲狀態欄提供通知,放在“正在進行”標題下方,這意味着除非服務停止或從前臺移除,否則不能清除通知。

例如,應該將通過服務播放音樂的音樂播放器設置爲在前臺運行,這是因爲用戶明確意識到其操作。 狀態欄中的通知可能表示正在播放的歌曲,並允許用戶啓動 Activity 來與音樂播放器進行交互。

要請求讓服務運行於前臺,請調用 startForeground()。此方法採用兩個參數:唯一標識通知的整型數和狀態欄的 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);
注意:提供給 startForeground() 的整型 ID 不得爲 0。

要從前臺移除服務,請調用 stopForeground()。此方法採用一個布爾值,指示是否也移除狀態欄通知。 此方法不會停止服務。 但是,如果您在服務正在前臺運行時將其停止,則通知也會被移除。

管理服務生命週期


服務的生命週期比 Activity 的生命週期要簡單得多。但是,密切關注如何創建和銷燬服務反而更加重要,因爲服務可以在用戶沒有意識到的情況下運行於後臺。

服務生命週期(從創建到銷燬)可以遵循兩條不同的路徑:

  • 啓動服務
    該服務在其他組件調用 startService() 時創建,然後無限期運行,且必須通過調用 stopSelf() 來自行停止運行。此外,其他組件也可以通過調用 stopService() 來停止服務。服務停止後,系統會將其銷燬。
  • 綁定服務
    該服務在另一個組件(客戶端)調用 bindService() 時創建。然後,客戶端通過 IBinder 接口與服務進行通信。客戶端可以通過調用 unbindService() 關閉連接。多個客戶端可以綁定到相同服務,而且當所有綁定全部取消後,系統即會銷燬該服務。 (服務不必自行停止運行。)
這兩條路徑並非完全獨立。也就是說,您可以綁定到已經使用 startService() 啓動的服務。例如,可以通過使用 Intent(標識要播放的音樂)調用 startService() 來啓動後臺音樂服務。隨後,可能在用戶需要稍加控制播放器或獲取有關當前播放歌曲的信息時,Activity 可以通過調用 bindService() 綁定到服務。在這種情況下,除非所有客戶端均取消綁定,否則 stopService() 或 stopSelf() 不會實際停止服務。

實現生命週期回調


與 Activity 類似,服務也擁有生命週期回調方法,您可以實現這些方法來監控服務狀態的變化並適時執行工作。 以下框架服務展示了每種生命週期方法:

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
    }
}
注:與 Activity 生命週期回調方法不同,您不需要調用這些回調方法的超類實現。



圖 2. 服務生命週期。左圖顯示了使用 startService() 所創建的服務的生命週期,右圖顯示了使用 bindService() 所創建的服務的生命週期。


通過實現這些方法,您可以監控服務生命週期的兩個嵌套循環:

  • 服務的整個生命週期從調用 onCreate() 開始起,到 onDestroy() 返回時結束。與 Activity 類似,服務也在 onCreate() 中完成初始設置,並在 onDestroy() 中釋放所有剩餘資源。例如,音樂播放服務可以在 onCreate() 中創建用於播放音樂的線程,然後在 onDestroy() 中停止該線程。
無論服務是通過 startService() 還是 bindService() 創建,都會爲所有服務調用 onCreate() 和 onDestroy() 方法。
  • 服務的有效生命週期從調用 onStartCommand() 或 onBind() 方法開始。每種方法均有 {Intent 對象,該對象分別傳遞到 startService() 或 bindService()。
對於啓動服務,有效生命週期與整個生命週期同時結束(即便是在 onStartCommand() 返回之後,服務仍然處於活動狀態)。對於綁定服務,有效生命週期在 onUnbind() 返回時結束。

注:儘管啓動服務是通過調用 stopSelf() 或 stopService() 來停止,但是該服務並無相應的回調(沒有 onStop() 回調)。因此,除非服務綁定到客戶端,否則在服務停止時,系統會將其銷燬 — onDestroy() 是接收到的唯一回調。

圖 2 說明了服務的典型回調方法。儘管該圖分開介紹通過 startService() 創建的服務和通過 bindService() 創建的服務,但是請記住,不管啓動方式如何,任何服務均有可能允許客戶端與其綁定。因此,最初使用 onStartCommand()(通過客戶端調用 startService())啓動的服務仍可接收對 onBind() 的調用(當客戶端調用 bindService() 時)。




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