Service的遠程調用

轉載:http://liangruijun.blog.51cto.com/3061169/653344/

Andorid平臺中,各個組件運行在自己的進程中,他們之間是不能相互訪問的,但是在程序之間是不可避免的要傳遞一些對象,在進程之間相互通信。爲了實現進程之間的相互通信,Andorid採用了一種輕量級的實現方式RPC(Remote Procedure Call 遠程進程調用)來完成進程之間的通信,並且Android通過接口定義語言(Andorid Interface Definition Language ,AIDL)來生成兩個進程之間相互訪問的代碼,例如,你在Activity裏的代碼需要訪問Service中的一個方法,那麼就可以通過這種方式來實現了。

   AIDL是Android的一種接口描述語言; 編譯器可以通過aidl文件生成一段代碼,通過預先定義的接口達到兩個進程內部通信進程的目的. 如果需要在一個Activity中, 訪問另一個Service中的某個對象, 需要先將對象轉化成 AIDL可識別的參數(可能是多個參數), 然後使用AIDL來傳遞這些參數, 在消息的接收端, 使用這些參數組裝成自己需要的對象。

   AIDL RPC機制是通過接口來實現的,類似Windows中的COM或者Corba,但他是輕量級的,客戶端和被調用實現之間是通過代理模式實現的,代理類和被代理類實現同一個接口Ibinder接口。

下面是實現Activity訪問Service例子的步驟:

一.創建.aidl文件

    AIDL使用簡單的語法來聲明接口,描述其方法以及方法的參數和返回值。這些參數和返回值可以是任何類型,甚至是其他AIDL生成的接口。重要的是必須導入導入除了內建類型(例如:int,boolean等)外的任何其他類型,哪怕是這些類型是在與接口相同的包中。具體的要求如下:

  • JAVA基本數據類型不需要導入
  • String,List,MapCharSequence不需要導入

使用Eclipse的ADT插件創建一個BookInfo.aidl文件,該文件有4個方法:

setName(String name)設置圖書的書名,setPrice(int price)設置圖書的價格,setPublish(String pname)設置圖書的出版社和String display()顯示圖書的信息.

BookInfo.aidl文件

  1. package com.android.aidl;  
  2.  
  3. //BookInfo接口  
  4. interface BookInfo{  
  5.       
  6.     void setName(String name);  
  7.     void setPrice(int price);  
  8.     void ssetPublish(String pname);  
  9.     //顯示圖書的信息  
  10.     String display();  

創建好BookInfo.aidl文件,系統會自動在gen目錄下生成Java接口文件BookInfo.java

二.實現AIDL文件生成的JAVA接口

    AIDL會生成一個和.aidl文件同名的JAVA接口文件,該接口中有一個靜態抽象內部類Stub,該類中聲明瞭AIDL文件中定義的所有方法,其中有一個重要的方法是asInterface(),該方法通過代理模式返回JAVA接口的實現我們可以定義一個實現類,BookImpl,該類繼承Stub類,實現我們定義的4個方法

  1. package com.android.aidl;  
  2. import android.os.RemoteException;  
  3.  
  4. public class BookInfoImpl extends BookInfo.Stub {  
  5.     //聲明三個個變量  
  6.     private int price;  
  7.     private String name,pname;  
  8.     //顯示書名,價格,出版社  
  9.     public String display() throws RemoteException{  
  10.         return "書名:"+name+";價格:"+price+";出版社:"+price;  
  11.     }  
  12.     @Override 
  13.     //設置書名  
  14.     public void setName(String name) throws RemoteException {  
  15.         // TODO Auto  
  16.         this.name= name;  
  17.     }  
  18.  
  19.     @Override 
  20.     //設置價格  
  21.     public void setPrice(int price) throws RemoteException {  
  22.         // TODO Auto-generated method stub  
  23.         this.price = price;  
  24.     }  
  25.     @Override 
  26.     //設置出版社  
  27.     public void setPublish(String pname) throws RemoteException {  
  28.         // TODO Auto  
  29.         this.pname= pname;  
  30.     }     
  31. }  

三.向客戶端暴露接口

現在已經實現了BookInfo接口,接下來要將該接口暴露給客戶端調用。一般通過定義一個Service來實現,在Service的onBind()方法中返回該接口,當我們綁定該接口時調用該方法。

  1. package com.android.aidl;  
  2.  
  3. import com.android.aidl.BookInfo.Stub;  
  4. import android.app.Service;  
  5. import android.content.Intent;  
  6. import android.os.IBinder;  
  7.  
  8. public class RemoteService extends Service {  
  9.     //聲明BookInfo接口  
  10.     private Stub bookifo = new BookInfoImpl();  
  11.     public IBinder onBind(Intent intent){  
  12.         return bookifo;  
  13.     }  

四.在客戶端調用

定義一個Activity來綁定遠程Service,獲得BookInfo接口,通過RPC機制調用接口中的方法。

  1. package com.android.aidl;  
  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.RemoteException;  
  11. import android.view.View;  
  12. import android.view.View.OnClickListener;  
  13. import android.widget.Button;  
  14. import android.widget.Toast;  
  15.  
  16. public class MainActivity extends Activity {  
  17.     // 聲明IPerson接口  
  18.     private BookInfo bookInfo;  
  19.     // 聲明 Button  
  20.     private Button btn;  
  21.     // 實例化ServiceConnection  
  22.     private ServiceConnection conn = new ServiceConnection() {  
  23.         @Override 
  24.         synchronized public void onServiceConnected(ComponentName name, IBinder service) {  
  25.             // 獲得IPerson接口  
  26.             bookInfo = BookInfo.Stub.asInterface(service);  
  27.             if (bookInfo != null)  
  28.                 try {  
  29.                     // RPC 方法調用  
  30.                     bookInfo.setName("Google Android SDK開發範例大全");  
  31.                     bookInfo.setPrice(55);  
  32.                     bookInfo.setPublish("人民郵電出版社");  
  33.                     String msg = bookInfo.display();  
  34.                     // 顯示方法調用返回值  
  35.                     Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG)  
  36.                             .show();  
  37.                 } catch (RemoteException e) {  
  38.                     e.printStackTrace();  
  39.                 }  
  40.         }  
  41.  
  42.         @Override 
  43.         public void onServiceDisconnected(ComponentName name) {  
  44.  
  45.         }  
  46.     };  
  47.  
  48.     @Override 
  49.     public void onCreate(Bundle savedInstanceState) {  
  50.         super.onCreate(savedInstanceState);  
  51.         // 設置當前視圖佈局  
  52.         setContentView(R.layout.main);  
  53.         // 實例化Button  
  54.         btn = (Button) findViewById(R.id.Button1);  
  55.         //爲Button添加單擊事件監聽器  
  56.         btn.setOnClickListener(new OnClickListener() {  
  57.             @Override 
  58.             public void onClick(View v) {  
  59.                 // 實例化Intent  
  60.                 Intent intent = new Intent();  
  61.                 // 設置Intent Action 屬性  
  62.                 intent.setAction("com.android.aidl.action.MY_REMOTE_SERVICE");  
  63.                 // 綁定服務  
  64.                 bindService(intent, conn, Service.BIND_AUTO_CREATE);  
  65.             }  
  66.         });  
  67.     }  

五.main.xml和AndroidManifest.xml文件

main.xml

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical" 
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     > 
  7.     <Button   
  8.         android:text="遠程調用Service"   
  9.         android:id="@+id/Button1"   
  10.         android:layout_width="wrap_content"   
  11.         android:layout_height="wrap_content" 
  12.         /> 
  13. </LinearLayout> 

在AndroidManifest.xml文件16~20聲明Service

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  3.       package="com.android.aidl" 
  4.       android:versionCode="1" 
  5.       android:versionName="1.0"> 
  6.     <uses-sdk android:minSdkVersion="10" /> 
  7.  
  8.     <application android:icon="@drawable/icon" android:label="@string/app_name"> 
  9.         <activity android:name=".MainActivity" 
  10.                   android:label="@string/app_name"> 
  11.             <intent-filter> 
  12.                 <action android:name="android.intent.action.MAIN" /> 
  13.                 <category android:name="android.intent.category.LAUNCHER" /> 
  14.             </intent-filter> 
  15.         </activity> 
  16.      <service android:name="RemoteService"> 
  17.             <intent-filter> 
  18.                 <action android:name="com.android.aidl.action.MY_REMOTE_SERVICE"/> 
  19.             </intent-filter> 
  20.     </service> 
  21.     </application> 
  22. </manifest> 

效果圖:


發佈了1 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章