Android Service


Service(服務)是一種在後台執行,執行長時間執行的操作,無需與使用者互動的元件。例如,一個服務可以在後台播放音樂,使用者在不同的應用程式或者可能通過網路獲取資料,而不阻塞使用者互動活動。本質上,一個服務可以採取兩種狀態:

狀態 描述
Started 當一個應用程式元件,如活動,開始通過呼叫StartService()啟動一個服務。開始以後服務可以無限期地在後台執行,即使啟動它的元件被破壞。
Bound 當一個應用程式元件系結呼叫bindService()方法系結服務。系結服務提供用戶端 - 伺服器的介面,允許元件進行互動的服務,傳送請求,得到結果,這樣可以跨進程進程間通訊(IPC)。

每個服務都具有生命週期回撥方法,可以實現監視服務的狀態變化,並在適當的階段執行工作。下圖左側顯示的整個生命周期由StartService()建立提供服務 ,右邊的圖顯示bindService()建立的整個生命週期提供服務:

Android Service lifecycle

要建立一個服務,需要建立一個Java類,擴充套件Service基礎類別或者它的子類。Service基礎類別定義各種回撥方法,如下面表格給出。但是也並不需要實現所有的回撥方法。重要的是要了解每一個變化以及實現,以確保應用程式能如使用者所期望的行為方式執行。

回撥 描述
onStartCommand() 系統呼叫此方法當另一元件,如一個活動,通過呼叫startService()要求該服務啟動。如果要實現方法,它工作完成後停止服務,通過呼叫stopSelf()或stopService()方法。
onBind() 該系統呼叫這個方法當其他元件要通過呼叫bindService()係結服務。如果實現此方法,必須提供用戶端與服務進行通訊,通過返回一個IBinder物件的介面。必須實現此方法,但如果不希望被繫結,那麼應該返回null。
onUnbind() 系統呼叫此方法,當所有客戶都從服務發布的特定介面斷開。
onRebind() 該系統呼叫這個方法時,新的用戶端已連線到服務,它事先未通知,所有已經上解除系結後(意向)斷開它。
onCreate() 該系統呼叫時,使用onStartCommand()或onBind()首先建立的服務這個方法。此呼叫需要執行一次性安裝。
onDestroy() 系統呼叫這個方法當服務不再使用(被銷毀)。服務應該實現這個用於清理,如執行緒,註冊的偵聽器,接收器等任何資源

下面的主服務演示每一個方法生命週期:

package com.yiibai;

import android.app.Service;
import android.os.IBinder;
import android.content.Intent;
import android.os.Bundle;

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

   /** Called when the service is being created. */
   @Override
   public void onCreate() {
     
   }

   /** The service is starting, due to a call to startService() */
   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
      return mStartMode;
   }

   /** A client is binding to the service with bindService() */
   @Override
   public IBinder onBind(Intent intent) {
      return mBinder;
   }

   /** Called when all clients have unbound with unbindService() */
   @Override
   public boolean onUnbind(Intent intent) {
      return mAllowRebind;
   }

   /** Called when a client is binding to the service with bindService()*/
   @Override
   public void onRebind(Intent intent) {

   }

   /** Called when The service is no longer used and is being destroyed */
   @Override
   public void onDestroy() {

   }
}

範例

這個例子將通過簡單的步驟顯示了如何建立Android服務。按照下面的步驟來修改前面章節建立的Android應用程式 - Hello World範例 :

步驟 描述
1 使用Eclipse IDE建立Android應用程式,並將其命名為HelloWorld在包com.example.helloworld下,類似Hello World範例章節中一樣。
2 修改主要活動檔案MainActivity.java新增startService()和stopService()方法。
3 在包com.example.helloworld下建立一個新的Java檔案MyService.java。該檔案將有實現Android服務相關的方法。
4 使用 <service.../>標籤定義AndroidManifest.xml檔案服務。一個應用可以有一個或多個服務,沒有任何限制。
5 修改res/layout/activity_main.xml檔案的預設內容包括線性布局中的兩個按鈕。
6 定義兩個常數start_service和stop_service在 res/values/strings.xml 檔案中
7 執行該應用程式啟動Android模擬器並驗證應用程式所做的修改結果。

以下是改性主要活動檔案 src/com.example.helloworld/MainActivity.java 的內容。這個檔案包括每個基本的生命周期方法。新增 StartService() stopService() 方法來啟動和停止服務。

package com.example.helloworld;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.content.Intent;
import android.view.View;

public class MainActivity extends Activity {

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
   }
   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      getMenuInflater().inflate(R.menu.activity_main, menu);
      return true;
   }

   // Method to start the service
   public void startService(View view) {
      startService(new Intent(getBaseContext(), MyService.class));
   }

   // Method to stop the service
   public void stopService(View view) {
      stopService(new Intent(getBaseContext(), MyService.class));
   }
}

以下是src/com.example.helloworld/MyService.java 的內容。這個檔案可以有一個或多個方法來使用服務。現在要實現只有兩個方法 onStartCommand() 和 onDestroy()  :

package com.example.helloworld;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;

public class MyService extends Service {
   @Override
   public IBinder onBind(Intent arg0) {
      return null;
   }

   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
      // Let it continue running until it is stopped.
      Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
      return START_STICKY;
   }
   @Override
   public void onDestroy() {
      super.onDestroy();
      Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
   }
}

下面將 AndroidManifest.xml 檔案的內容修改。在這裡新增 <service.../> 標籤,包括服務:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.helloworld"
   android:versionCode="1"
   android:versionName="1.0" >
   <uses-sdk
      android:minSdkVersion="8"
      android:targetSdkVersion="15" />
   <application
       android:icon="@drawable/ic_launcher"
       android:label="@string/app_name"
       android:theme="@style/AppTheme" >
       <activity
           android:name=".MainActivity"
           android:label="@string/title_activity_main" >
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER"/>
           </intent-filter>
       </activity>
       <service android:name=".MyService" />
   </application>
</manifest>

將以下是 res/layout/activity_main.xml 檔案的內容,包括兩個按鈕:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical" >

   <Button android:id="@+id/btnStartService"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/start_service"
   android:onClick="startService"/>

   <Button android:id="@+id/btnStopService"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/stop_service"
   android:onClick="stopService" />

</LinearLayout>

下面將在 res/values/strings.xml 中定義兩個新的常數: 

<resources>

    <string name="app_name">HelloWorld</string>
    <string name="hello_world">Hello world!</string>
    <string name="menu_settings">Settings</string>
    <string name="title_activity_main">MainActivity</string>
    <string name="start_service">Start Service</string>
    <string name="stop_service">Stop Service</string>

</resources>

現在執行修改後的 Hello World!應用程式。假設建立了AVD 並同時做了環境設定。要在Eclipse執行的應用程式,開啟一個專案的活動檔案,從工具列上找到並單擊 “run”  Eclipse Run Icon圖示。 Eclipse AVD上安裝的應用程式,並啟動它,如果一切設定以及應用都沒有問題,那麼將會顯示以下模擬器視窗:

Android Service Demo

要開始服務,現在就點選啟動服務按鈕,onStartCommand() 方法在程式中,每一個服務開始後將出現訊息在模擬器底部,如下:

Android Service Start

要停止該服務,可以點選停止服務(Stop Service)按鈕。