Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android應用開發入門(四十八)綁定Service進行數據交互的幾種方法

Android應用開發入門(四十八)綁定Service進行數據交互的幾種方法

編輯:Android開發實例

前言

  本文介紹一下Android下使用綁定服務進行時數據交互的幾種方法。關於Android下Service的內容,前面兩篇已經介紹了,不清楚的可以移步過去先看看:http://www.fengfly.com/plus/view-214081-1.html 、http://www.fengfly.com/plus/view-214082-1.html。

  在前面的文章中已經介紹到了,對於Service組件而言,它只有在綁定模式下才可以與客戶端進行時交互,這裡講解幾個方法進行綁定服務與客戶端間的交互方法:

  1. 使用IBinder接口
  2. 使用Messenger類
  3. 使用AIDL

  雖然根據官方文檔給出了三個方法,其中AIDL涉及的內容超出本博客內容范圍,以後有機會在另外介紹,本文只介紹1、2兩種方式的數據交互。

 

使用IBinder接口

  如果看了之前關於Service博客的人,應該對IBinder接口有所了解,這裡簡單介紹一下IBinder。

  IBinder是遠程對象的基本接口,是為高性能而設計的輕量級遠程調用機制的核心部分。但它不僅用於遠程調用,也可以用於進程內調用。這個接口定義了與遠程對象交互的協議,一般不直接實現這個接口,而是從它的實現類Binder中繼承。

  通過IBinder進行服務的交互一般有兩種方式,一種方式是使用IBinder.transact()方法向遠端的IBinder對象發送一個發出調用,會回調遠端的Binder.onTransact()方法,這個方法傳遞的數據是Parcel。Parcel是一種緩沖區,除了數據外還有有一些描述它內容的元素,如果查看源碼的話會發現,Parcel本質上是一個Serialize,只是它在內存中完成了序列化和反序列化,利用的是連續的內存空間,因此效率會更高,並且AIDL的數據也是通過Parcel來交互的。另外一種方法就是拋棄IBinder中原生的方法,使用自定義的接口方法進行數據交互,這也是Android官方推薦綁定服務的一種數據交互方式。當然,不管是使用transact()給遠程服務交互,還是使用自定義的接口交互,都是同步執行的,直到遠程服務執行完並返回結果才會繼續向下執行。

  其他關於適應IBinder服務的內容,在http://www.fengfly.com/plus/view-214081-1.html 中已經講解過了,這裡不再累述。下面使用一個例子來演示一下使用自定義接口與服務進行交互的例子。

  服務:IBinderSer.java

  1. package cn.bgxt.servicebinddatedemo;  
  2.  
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.Binder;  
  6. import android.os.IBinder;  
  7. import android.os.Parcel;  
  8. import android.os.RemoteException;  
  9. import android.util.Log;  
  10.  
  11. public class IBinderSer extends Service {  
  12.     private final String TAG="main";  
  13.     private final int MULTIPLE=1024;      
  14.     public  final IBinder mBinder=new LocalBinder();  
  15.       
  16.     public class LocalBinder extends Binder{  
  17.         // 在Binder中定義一個自定義的接口用於數據交互  
  18.         // 這裡直接把當前的服務傳回給宿主  
  19.         public IBinderSer getService(){  
  20.             return IBinderSer.this;  
  21.         }                  
  22.     }  
  23.       
  24.     @Override 
  25.     public IBinder onBind(Intent intent) {  
  26.         Log.i(TAG, "The service is binding!");  
  27.         // 綁定服務,把當前服務的IBinder對象的引用傳遞給宿主  
  28.         return mBinder;  
  29.     }  
  30.       
  31.     public int getMultipleNum(int num){  
  32.         // 定義一個方法 用於數據交互  
  33.         return MULTIPLE*num;  
  34.     }  

  調用服務的Activity:IBinderActivity.java

  1. package cn.bgxt.servicebinddatedemo;  
  2.  
  3. import android.app.Activity;  
  4. import android.app.Service;  
  5. import android.content.ComponentName;  
  6. import android.content.Intent;  
  7. import android.content.ServiceConnection;  
  8. import android.os.Bundle;  
  9. import android.os.IBinder;  
  10. import android.os.Messenger;  
  11. import android.os.Parcel;  
  12. import android.os.RemoteException;  
  13. import android.view.View;  
  14. import android.widget.Button;  
  15. import android.widget.Toast;  
  16.  
  17. public class IBinderActivity extends Activity {  
  18.     private Button btnStart, btnInvoke, btnStop;  
  19.     IBinderSer mService=null;  
  20.     private ServiceConnection mConnection = new ServiceConnection() {  
  21.  
  22.         @Override 
  23.         public void onServiceDisconnected(ComponentName name) {  
  24.             mService = null;  
  25.         }  
  26.  
  27.         @Override 
  28.         public void onServiceConnected(ComponentName name, IBinder service) {  
  29.             // 獲取服務上的IBinder對象,調用IBinder對象中定義的自定義方法,獲取Service對象  
  30.             IBinderSer.LocalBinder binder=(IBinderSer.LocalBinder)service;  
  31.             mService=binder.getService();  
  32.         }  
  33.     };  
  34.       
  35.     @Override 
  36.     protected void onCreate(Bundle savedInstanceState) {  
  37.         super.onCreate(savedInstanceState);  
  38.         setContentView(R.layout.layout_service);  
  39.         btnStart = (Button) findViewById(R.id.btnStartSer);  
  40.         btnInvoke = (Button) findViewById(R.id.btnInvokeMethod);  
  41.         btnStop = (Button) findViewById(R.id.btnStopSer);  
  42.           
  43.         btnStart.setOnClickListener(onclick);  
  44.         btnInvoke.setOnClickListener(onclick);  
  45.         btnStop.setOnClickListener(onclick);  
  46.     }  
  47.  
  48.     View.OnClickListener onclick = new View.OnClickListener() {  
  49.  
  50.         @Override 
  51.         public void onClick(View v) {  
  52.             switch (v.getId()) {  
  53.             case R.id.btnStartSer:  
  54.                 Toast.makeText(getApplicationContext(), "綁定服務成功", Toast.LENGTH_SHORT).show();  
  55.                 bindService(new Intent(IBinderActivity.this,IBinderSer.class),mConnection,Service.BIND_AUTO_CREATE);                  
  56.                 break;  
  57.             case R.id.btnInvokeMethod:  
  58.                 if(mService==null){  
  59.                     Toast.makeText(getApplicationContext(), "請先綁定服務", Toast.LENGTH_SHORT).show();  
  60.                     return;  
  61.                 }  
  62.                 // 調用綁定服務上的方法,進行數據交互  
  63.                 int iResult=mService.getMultipleNum(10);  
  64.                 Toast.makeText(getApplicationContext(), "服務計算結果為:"+iResult, Toast.LENGTH_SHORT).show();  
  65.                 break;  
  66.             case R.id.btnStopSer:  
  67.                 Toast.makeText(getApplicationContext(), "服務解除綁定", Toast.LENGTH_SHORT).show();  
  68.                 unbindService(mConnection);  
  69.                 mService=null;  
  70.                 break;  
  71.             default:  
  72.                 break;  
  73.             }  
  74.         }  
  75.     };  

執行結果:

 

使用Messenger類

  除了使用IBinder之外,還可以使用Messenger,那麼先來聊聊什麼是Messenger。

  Messenger引用了一個Handler獨享,可以使用Messenger.send(Message msg)方法跨進程向服務發送消息,只需要在服務中使用Handler創建一個Messenger,宿主持有這個Messenger就可以與服務進行通信。之前介紹的handler+Message的通信方式不同,那都是在同一個進程中的,從工作線程持有一個主線程的Handler對象,從而向主線程發送消息,這裡不了解的可以看看之前的http://www.fengfly.com/plus/view-213516-1.html。而上面介紹過了,Android可以使用IBinder實現跨進程通信,並且也將Handler與IBinder結合起來實現跨進程發送消息。

  當然這裡提一下,Messenger管理的是一個消息隊列,它會依據消息進入的先後次序予以執行,所以也不需要把服務設計為線程安全是。

   實現Messenger實現進程通信,主要有以下幾點注意:

  1. 在服務中實現一個Handler類,並實例化它,在handleMessage()方法中接收客戶端的請求。
  2. 在服務中使用這個Handler對象創建一個Messenger對象。
  3. 使用Messenger對象的getBinder()方法返回一個IBinder對象作為onBind()的返回值返回給客戶端。
  4. 在客戶端使用IBinder實例化一個Messenger對象,並使用它向服務端發送信息。

  下面通過一個簡單的例子來演示一下利用Messenger在服務與客戶端進行的通信。

  服務:MessengerSer.java

  1. package cn.bgxt.servicebinddatedemo;  
  2.  
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.Handler;  
  6. import android.os.IBinder;  
  7. import android.os.Message;  
  8. import android.os.Messenger;  
  9. import android.util.Log;  
  10. import android.widget.Toast;  
  11.  
  12. public class MessengerSer extends Service {  
  13.     private final String TAG="main";  
  14.     static final int MSG_SAY_HELLO = 1;  
  15.  
  16.     public class IncomingHandler extends Handler {  
  17.         @Override 
  18.         public void handleMessage(Message msg) {  
  19.             switch (msg.what) {  
  20.             case MSG_SAY_HELLO:  
  21.                 Toast.makeText(getApplicationContext(), "Service say hello!",  
  22.                         Toast.LENGTH_SHORT).show();  
  23.                 Log.i(TAG, "Service say hello!");  
  24.                 break;  
  25.             default:  
  26.                 super.handleMessage(msg);  
  27.             }  
  28.         }  
  29.     }  
  30.  
  31.     IncomingHandler incomingHandler=new IncomingHandler();  
  32.      final Messenger mMessenger=new Messenger(new IncomingHandler());  
  33.        
  34.     @Override 
  35.     public IBinder onBind(Intent arg0) {  
  36.         return mMessenger.getBinder();  
  37.     }  
  38.  

 

  服務綁定的Activity:MessengerActivity.java

  1. package cn.bgxt.servicebinddatedemo;  
  2.  
  3.  
  4. import android.app.Activity;  
  5. import android.app.Service;  
  6. import android.content.ComponentName;  
  7. import android.content.Intent;  
  8. import android.content.ServiceConnection;  
  9. import android.os.Bundle;  
  10. import android.os.IBinder;  
  11. import android.os.Message;  
  12. import android.os.Messenger;  
  13. import android.os.RemoteException;  
  14. import android.view.View;  
  15. import android.widget.Button;  
  16. import android.widget.Toast;  
  17.  
  18. public class MessengerActivity extends Activity {  
  19.     private Button btnStart, btnInvoke, btnStop;  
  20.     private Messenger mService = null;  
  21.  
  22.     private ServiceConnection mConnection = new ServiceConnection() {  
  23.  
  24.         @Override 
  25.         public void onServiceDisconnected(ComponentName name) {  
  26.             mService = null;  
  27.         }  
  28.  
  29.         @Override 
  30.         public void onServiceConnected(ComponentName name, IBinder service) {  
  31.             // 使用服務端的IBinder對象實例化一個Messenger對象  
  32.             mService = new Messenger(service);  
  33.         }  
  34.     };  
  35.     @Override 
  36.     protected void onCreate(Bundle savedInstanceState) {  
  37.         // TODO Auto-generated method stub  
  38.         super.onCreate(savedInstanceState);  
  39.         setContentView(R.layout.layout_service);  
  40.         btnStart = (Button) findViewById(R.id.btnStartSer);  
  41.         btnInvoke = (Button) findViewById(R.id.btnInvokeMethod);  
  42.         btnStop = (Button) findViewById(R.id.btnStopSer);  
  43.           
  44.         btnStart.setOnClickListener(onclick);  
  45.         btnInvoke.setOnClickListener(onclick);  
  46.         btnStop.setOnClickListener(onclick);  
  47.     }  
  48.  
  49.     View.OnClickListener onclick = new View.OnClickListener() {  
  50.  
  51.         @Override 
  52.         public void onClick(View v) {  
  53.             switch (v.getId()) {  
  54.             case R.id.btnStartSer:  
  55.                 Toast.makeText(getApplicationContext(), "綁定服務成功", Toast.LENGTH_SHORT).show();  
  56.                 bindService(new Intent(getApplicationContext(),MessengerSer.class), mConnection, Service.BIND_AUTO_CREATE);  
  57.                 break;  
  58.             case R.id.btnInvokeMethod:  
  59.                 if(mService==null){  
  60.                     Toast.makeText(getApplicationContext(), "請先綁定服務",Toast.LENGTH_SHORT).show();  
  61.                     return ;  
  62.                 }  
  63.                 // 實例化一個Message對象  
  64.                 Message msg=Message.obtain(null, MessengerSer.MSG_SAY_HELLO, 0, 0);  
  65.                 try{  
  66.                     // 把Message獨享傳遞給服務端處理  
  67.                     mService.send(msg);  
  68.                 }  
  69.                 catch(RemoteException e){  
  70.                     e.printStackTrace();  
  71.                 }  
  72.                 break;  
  73.             case R.id.btnStopSer:  
  74.                 Toast.makeText(getApplicationContext(), "服務解除綁定", Toast.LENGTH_SHORT).show();  
  75.                 unbindService(mConnection);  
  76.                 mService=null;  
  77.                 break;  
  78.             default:  
  79.                 break;  
  80.             }  
  81.  
  82.         }  
  83.     };  

 

  執行結果:

 

 

使用AIDL

  AIDL(Android Interface Definition Language),它可以實現跨進程間的通信。之前講到的Messenger實現跨進程通信,其實也是基於AIDL作為底層結構。但是正如上面提到的,Messenger創建的一個消息隊列是在一個單獨的線程中,所以服務一次僅處理一個請求,然而,如果想要服務同時處理多個請求,就需要使用到AIDL,但是這種情況下就要考慮多線程和線程安全的問題了。這個不在本篇博客的范疇內,以後有機會在細細講解。

 

  源碼下載

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