Android Service 之三(Bind Service, 繼承自 Binder 類)

 之前提及過,啟動Service有兩種方式:startService 與 bindService。前者已經說過如何使用,所以,這篇貼子主要是關於 bind service的。 這裡所討論的是僅針對那些被綁定的service的,而那些既被startService() 又被 bindService() 的 service 不在此範圍內。

① Bind Service就像是C/S架構中的服務端,其他組件(比如 Activity)綁定到它(通過 bindService()),可以向它發送請求,可以接受從它返回的響應,它甚至還提供了進程間通信(IPC)功能。

② 一個service要想能夠被其他組件綁定,那麼它的 onBind() 方法必須被實現,且必須返回一個 IBinder 對象,然後其他組件可以通過這個 IBinder 對象與該 service 進行通訊。

③ 多個client可以綁定至同一個service,但該 service 的onBind() 方法只會在第一個 client 綁定至其的時候被調用,當其他 client 再次綁定到它的時候,並不會調用  onBind() 方法,而是直接返回第一次被調用時產生的那個 IBinder 對象。也就是說,在其生命週期內,onBind() 只會被調用一次。

④ Bind Service 的生命週期如下圖所示:



 

⑤ Bind Service 不會在後臺無限期的一直運行,而是當所有綁定至其的組件都調用了 unbindService() 進行解綁之後,系統就會將其停掉以回收資源。

 

⑥ 當我們要實現一個 Bind Service 的時候,最重要的就是實現它的 onBind() 方法以返回一個 IBinder 對象

 

要生成一個 Bound Service ,共有三種方式:繼承自 Binder 類,使用 Messenger ,使用 AIDL。下面且聽小生一一道來。

第一種:繼承自 Binder 類

需要注意的是,這種方式僅僅適用於這種場合:service 與 application 在同一個進程中。這種場合也是最最常見的。

它分以下幾個步驟:

a. 在你的 service 類中聲明一個內部類來繼承 Binder 類。在該內部類中,最好提供一個公共方法來返回你的 service 實例。

b. 在你的 service 類中需要聲明一個這個內部類的實例,以供在 onBind() 方法中返回

c. 在 client 端,在 onServiceConnected() 方法中得到從 onBind() 方法中返回的 IBinder 對象,然後可以通過該 對象中的公共方法得到相應的 service 實例,正如 第一個步驟 所說的那樣。

d. 在 service 中提供公共方法, 這樣就可以在組件(如 Activity 中調用這些公共方法了)

 

下面給出一例:

service 代碼

Java代碼   收藏代碼
  1. public class BindServiceWithIBinder extends Service {  
  2.   
  3.     private static final String TAG = "BindServiceWithIBinder";  
  4.   
  5.     private final MyIBinder myIBinder = new MyIBinder();  
  6.   
  7.     /** 
  8.      * bindService() 時,調用的是這個方法,而非 onStartCommnad() 方法 
  9.      */  
  10.     @Override  
  11.     public IBinder onBind(Intent intent) {  
  12.         // 在主 Activity 上的 TextView 中打印出一行LOG  
  13.         MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  14.                 MyServiceActivity.UPDATE_VIEW, TAG + " ----> onBind"));  
  15.         return myIBinder;  
  16.     }  
  17.   
  18.     @Override  
  19.     public void onCreate() {  
  20.         MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  21.                 MyServiceActivity.UPDATE_VIEW, TAG + " ----> onCreate"));  
  22.     }  
  23.   
  24.     @Override  
  25.     public void onDestroy() {  
  26.         MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  27.                 MyServiceActivity.UPDATE_VIEW, TAG + " ----> onDestroy"));  
  28.     }  
  29.   
  30.     @Override  
  31.     public void onRebind(Intent intent) {  
  32.         MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  33.                 MyServiceActivity.UPDATE_VIEW, TAG + " ----> onRebind"));  
  34.     }  
  35.   
  36.     @Override  
  37.     public int onStartCommand(Intent intent, int flags, int startId) {  
  38.         MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  39.                 MyServiceActivity.UPDATE_VIEW, TAG + " ----> onStartCommand"));  
  40.         return START_STICKY;  
  41.     }  
  42.   
  43.     @Override  
  44.     public boolean onUnbind(Intent intent) {  
  45.         MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  46.                 MyServiceActivity.UPDATE_VIEW, TAG + " ----> onUnbind"));  
  47.         return super.onUnbind(intent);  
  48.     }  
  49.   
  50.     /** 
  51.      * 聲明一個 Binder 類的實現類,供在 onBind() 方法中返回該類的一個實例 
  52.      * @author 001718 
  53.      * 
  54.      */  
  55.     public class MyIBinder extends Binder {  
  56.         public Service getService() {  
  57.             MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  58.                     MyServiceActivity.UPDATE_VIEW,  
  59.                     "BindServiceWithIBinder.MyIBinder.getService()"));  
  60.             return BindServiceWithIBinder.this;  
  61.         }  
  62.     }  
  63.   
  64.     /** 
  65.      * service 提供的公共方法,在activity中可以調用 
  66.      */  
  67.     public void download() {  
  68.         try {  
  69.             MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  70.                     MyServiceActivity.UPDATE_VIEW, TAG  
  71.                             + " ----> download(): 文件下載中..."));  
  72.             Thread.sleep(3000);  
  73.             MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  74.                     MyServiceActivity.UPDATE_VIEW, TAG  
  75.                             + " ----> download(): 文件下載完成..."));  
  76.         } catch (InterruptedException e) {  
  77.             e.printStackTrace();  
  78.         }  
  79.     }  
  80. }  

 主 Activity 中的相應關鍵代碼為:

Java代碼   收藏代碼
  1. private void doUnbindService() {  
  2.         if (isBound) {  
  3.             unbindService(myLocalServiceConnection);  
  4.             isBound = false;  
  5.         }  
  6.     }  
  7.   
  8.     private void doBindService() {  
  9.         Log.i("bind""begin to bind");  
  10.         bindService(intent, myLocalServiceConnection, Context.BIND_AUTO_CREATE);  
  11.   
  12.     }  
  13.   
  14.     private ServiceConnection myLocalServiceConnection = new ServiceConnection() {  
  15.         public void onServiceConnected(android.content.ComponentName name,  
  16.                 android.os.IBinder service) {  
  17.             MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  18.                     MyServiceActivity.UPDATE_VIEW,  
  19.                     "myServiceConnection.onServiceConnected"));  
  20.             // 因為 客戶端 與 服務 在同一個進程內,這樣一來,就可以知道參數 "service"的類型了,也就可以進行顯示的強制類型轉換了。  
  21.             // 而如果 客戶端與服務不在同一個進程中的話,那麼此處是不可以進行顯示強制類型轉換的,  
  22.             // 因為,通過Debug,可以發現此時傳進來的 Service 的類型是 BinderProxy  
  23.             MyIBinder myIBinder = (MyIBinder) service;  
  24.             bsi = (BindServiceWithIBinder) myIBinder.getService();  
  25.             isBound = true;  
  26.   
  27.             bsi.download();  
  28.         };  
  29.   
  30.         public void onServiceDisconnected(android.content.ComponentName name) {  
  31.             MyServiceActivity.vh.sendMessage(MyServiceActivity.createMessage(  
  32.                     MyServiceActivity.UPDATE_VIEW,  
  33.                     "myServiceConnection.onServiceDisconnected"));  
  34.             isBound = false;  
  35.         };  
  36.     };  

书籍推荐