Android(java)學習筆記175:Android進程間通信(IPC)之AIDL

1、IPCjava

inter process communication  進程間通信android

2、AIDLapp

android  interface  defination  language  安卓接口定義語言框架

知足兩個進程之間  接口數據的交換(ipc)ide

 

首先咱們搞清楚兩個概念  遠程服務和本地服務 ?佈局

           本地服務:服務的代碼在應用程序工程的內部this

           遠程服務:服務的代碼在另外一個應用程序的裏面spa

 

3、下面經過案例說明AIDL(IPC)在遠程服務中使用3d

1.首先建立一個Android項目,命名爲"遠程服務";代理

(1)工程一欄表以下:

(2)既然是遠程服務,咱們就先建立遠程服務爲RemoteServiceDemo.java,同時也須要在AndroidMainfest.xml的清單文件中註冊,以下:

AndroidMainfest.xml:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="com.himi.remoteservice"
 4     android:versionCode="1"
 5     android:versionName="1.0" >
 6 
 7     <uses-sdk
 8         android:minSdkVersion="15"
 9         android:targetSdkVersion="17" />
10 
11     <application
12         android:allowBackup="true"
13         android:icon="@drawable/ic_launcher"
14         android:label="@string/app_name"
15         android:theme="@style/AppTheme" >
16         <activity
17             android:name=".MainActivity"
18             android:label="@string/app_name" >
19             <intent-filter>
20                 <action android:name="android.intent.action.MAIN" />
21 
22                 <category android:name="android.intent.category.LAUNCHER" />
23             </intent-filter>
24         </activity>
25         <service android:name="com.himi.remoteservice.RemoteServiceDemo">
26             <intent-filter >
27                 <action android:name="com.himi.remoteservice"/>
28             </intent-filter>
29         </service>
30     </application>
31 
32 </manifest>

這裏咱們定義了service的action,這是由於假若應用程序本身調用服務直接使用顯式意圖便可,也就是以下這種形式:

Intent intent = new Intent(this,Service.class);

startActivity(intent);

可是,咱們這裏是本身定義的遠程服務程序,也就是這個程序在遠程,讓本地(或者其餘用戶)去調用的,因此這裏使用了隱式意圖。

 

與此同時,咱們編寫RemoteServiceDemo.java代碼以下:

 1 package com.himi.remoteservice;  2 
 3 import android.app.Service;  4 import android.content.Intent;  5 import android.os.Binder;  6 import android.os.IBinder;  7 
 8 public class RemoteServiceDemo extends Service {  9     
10     private class MyBinder extends Binder implements IService { 11 
12         public void callMethodInService() { 13  methodInservice(); 14             
15  } 16         
17  } 18 
19  @Override 20     public IBinder onBind(Intent intent) { 21         System.out.println("遠程的服務被綁定 onBind"); 22         return new MyBinder(); 23  } 24 
25  @Override 26     public boolean onUnbind(Intent intent) { 27         System.out.println("遠程的服務被解除綁定 onUnbind"); 28         return super.onUnbind(intent); 29  } 30     
31  @Override 32     public void onCreate() { 33         System.out.println("遠程的服務onCreate"); 34         super.onCreate(); 35  } 36     
37  @Override 38     public void onDestroy() { 39         System.out.println("遠程的服務onDestroy"); 40         super.onDestroy(); 41  } 42     
43     public void methodInservice() { 44         System.out.println("我是遠程服務裏面的方法,我被調用了"); 45  } 46 }

這裏咱們定義的methodInservice(),是遠程服務中的方法這也是本地用戶(或者其餘用戶)但願調用和訪問的方法。

如今咱們的需求,就是能夠由別的用戶程序調用這個methodInservice()方法

 

上面接口IService.java爲以下:

1 package com.himi.remoteservice; 2 
3 public interface IService { 4 
5     public void callMethodInService(); 6 }

(3)其餘的MainActivity和activity_main佈局文件咱們這裏沒有修改

(4)這樣一個遠程的服務就搭建好了

工程一覽表以下:

 

2.接下來咱們再新建一個Android項目,命名爲" 調用遠程服務的方法 ",以下:

(1)項目一覽表:

(2)先編寫佈局文件activity_main.xml,以下:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2  xmlns:tools="http://schemas.android.com/tools"
 3  android:layout_width="match_parent"
 4  android:layout_height="match_parent"
 5  android:orientation="vertical"
 6  tools:context="com.himi.remotecall.MainActivity" >
 7 
 8     <Button  9         android:onClick="bind"
10  android:layout_width="match_parent"
11  android:layout_height="wrap_content"
12  android:text="綁定遠程服務" />
13      <Button 14         android:onClick="call"
15  android:layout_width="match_parent"
16  android:layout_height="wrap_content"
17  android:text="調用遠程服務方法" />
18 
19 </LinearLayout>

佈局效果以下:

(3)實現一下MainActivity裏面的代碼,以下:

 1 package com.himi.remotecall;  2 
 3 import android.app.Activity;  4 import android.content.ComponentName;  5 import android.content.Intent;  6 import android.content.ServiceConnection;  7 import android.os.Bundle;  8 import android.os.IBinder;  9 import android.view.View; 10 
11 public class MainActivity extends Activity { 12     private MyConn conn; 13 
14  @Override 15     protected void onCreate(Bundle savedInstanceState) { 16         super.onCreate(savedInstanceState); 17  setContentView(R.layout.activity_main); 18  } 19 
20     /**
21  * 綁定遠程服務 22  * @param view 23      */
24     public void bind(View view) { 25         Intent service = new Intent(); 26         service.setAction("com.himi.remoteservice"); 27         conn = new MyConn(); 28  bindService(service, conn, BIND_AUTO_CREATE); 29  } 30     
31     private class MyConn implements ServiceConnection { 32 
33         public void onServiceConnected(ComponentName name, IBinder service) { 34             
35  } 36 
37         public void onServiceDisconnected(ComponentName name) { 38 
39  } 40         
41  } 42     
43     public void call(View view) { 44         
45  } 46 }

這個客戶端訪問遠程服務的框架,咱們搭建好了;

可是咱們不能訪問遠端的服務方法,由於這裏的

public void onServiceConnected(ComponentName name, IBinder service),這個方法是綁定服務成功的時候調用的,Service.java會反饋一個IBinder service的信息,可是咱們這裏並不像遠程服務那樣,具有這個IService的接口,經過接口類型轉化,也就是以下:

 IService iService = (IService)service;

 iService.callMethodInService();

如今不能這樣調用methodInservice()方法,由於根本就不能接收到 IBinder service

因此不能調用遠程服務的methodInservice()方法

 

3.該怎麼辦?如何調用遠程服務方法這裏要利用到AIDL(IPC)

(1)第一步,咱們回到"遠程服務」的項目,以下:

IService.java文件在工程目錄下的路徑,以下:

找到這個路徑以下:

看到上面的IService.java文件了,這裏咱們修改它的擴展名,由java 改爲 aidl,以下:

回到"遠程服務"這個工程,刷新它,結果以下:

 

這會咱們發現這裏的IService.java變成了IService.aidl,可是報錯了,不用擔憂咱們慢慢修改錯誤;

(2)來到IService.aidl文件下,以下:

aidl做爲兩個進程之間的接口,固然是共有的,不是共有的沒法互相通訊了,這裏aidl中沒有權限修飾符,因此刪除上下兩個public,結果以下:

如今IService.aidl文件也就不報錯了;

(3)接着,咱們來到RemoteServiceDemo.java以下:

修改爲以下形式,便可:

 

爲何這樣修改?

相應咱們在gen目錄下,生成一個IService.java,以下:

由於IService.Stub在gen目錄下生成的IService.java的實現了接口com.himi.remoteservice.IService,同時繼承了android.os.Binder,以下:

 1 /*
 2  * This file is auto-generated. DO NOT MODIFY.  3  * Original file: C:\\Users\\Administrator.GDIZOK2X2LA0SQG\\workspace\\遠程服務\\src\\com\\himi\\remoteservice\\IService.aidl  4  */
 5 package com.himi.remoteservice;  6 public interface IService extends android.os.IInterface  7 {  8 /** Local-side IPC implementation stub class. */
 9 public static abstract class Stub extends android.os.Binder implements com.himi.remoteservice.IService 10 { 11 private static final java.lang.String DESCRIPTOR = "com.himi.remoteservice.IService"; 12 /** Construct the stub at attach it to the interface. */
13 public Stub() 14 { 15 this.attachInterface(this, DESCRIPTOR); 16 } 17 /**
18  * Cast an IBinder object into an com.himi.remoteservice.IService interface, 19  * generating a proxy if needed. 20  */
21 public static com.himi.remoteservice.IService asInterface(android.os.IBinder obj) 22 { 23 if ((obj==null)) { 24 return null; 25 } 26 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 27 if (((iin!=null)&&(iin instanceof com.himi.remoteservice.IService))) { 28 return ((com.himi.remoteservice.IService)iin); 29 } 30 return new com.himi.remoteservice.IService.Stub.Proxy(obj); 31 } 32 @Override public android.os.IBinder asBinder() 33 { 34 return this; 35 } 36 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 37 { 38 switch (code) 39 { 40 case INTERFACE_TRANSACTION: 41 { 42 reply.writeString(DESCRIPTOR); 43 return true; 44 } 45 case TRANSACTION_callMethodInService: 46 { 47 data.enforceInterface(DESCRIPTOR); 48 this.callMethodInService(); 49 reply.writeNoException(); 50 return true; 51 } 52 } 53 return super.onTransact(code, data, reply, flags); 54 } 55 private static class Proxy implements com.himi.remoteservice.IService 56 { 57 private android.os.IBinder mRemote; 58 Proxy(android.os.IBinder remote) 59 { 60 mRemote = remote; 61 } 62 @Override public android.os.IBinder asBinder() 63 { 64 return mRemote; 65 } 66 public java.lang.String getInterfaceDescriptor() 67 { 68 return DESCRIPTOR; 69 } 70 @Override public void callMethodInService() throws android.os.RemoteException 71 { 72 android.os.Parcel _data = android.os.Parcel.obtain(); 73 android.os.Parcel _reply = android.os.Parcel.obtain(); 74 try { 75 _data.writeInterfaceToken(DESCRIPTOR); 76 mRemote.transact(Stub.TRANSACTION_callMethodInService, _data, _reply, 0); 77 _reply.readException(); 78 } 79 finally { 80 _reply.recycle(); 81 _data.recycle(); 82 } 83 } 84 } 85 static final int TRANSACTION_callMethodInService = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 86 } 87 public void callMethodInService() throws android.os.RemoteException; 88 }

 

(4)這樣"遠端服務",咱們就修改好了,以下潔白無瑕:

 

4. 接着回到"調用遠程服務的方法」這個項目下:

(1)在src目錄下,建立一個包名,這個包名要  和 遠程服務下的RemoteServiceDemo.java的包名一致, 這裏都是com.himi.remoteservice,以下:

 

 

(2)把工程"遠程服務"中的IService.aidl   複製到  工程」調用遠程服務的方法"的src/com.himi.remoteservice,以下:

工程」調用遠程服務的方法"的gen目錄下也生成了IService.java

(3)回到工程」調用遠程服務的方法"的MainActivity,編寫代碼以下:

 1 package com.himi.remotecall;  2 
 3 import com.himi.remoteservice.IService;  4 
 5 import android.app.Activity;  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.RemoteException; 12 import android.view.View; 13 
14 public class MainActivity extends Activity { 15     private MyConn conn; 16     private IService iservice; 17  @Override 18     protected void onCreate(Bundle savedInstanceState) { 19         super.onCreate(savedInstanceState); 20  setContentView(R.layout.activity_main); 21  } 22 
23     /**
24  * 綁定遠程服務 25  * @param view 26      */
27     public void bind(View view) { 28         Intent service = new Intent(); 29         service.setAction("com.himi.remoteservice"); 30         conn = new MyConn(); 31  bindService(service, conn, BIND_AUTO_CREATE); 32  } 33     
34     private class MyConn implements ServiceConnection { 35 
36         public void onServiceConnected(ComponentName name, IBinder service) { 37            iservice = IService.Stub.asInterface(service); 38  } 39 
40         public void onServiceDisconnected(ComponentName name) { 41 
42  } 43         
44  } 45     
46     public void call(View view) { 47         try { 48  iservice.callMethodInService(); 49         } catch (RemoteException e) { 50             // TODO 自動生成的 catch 塊
51  e.printStackTrace(); 52  } 53  } 54 }

(4)佈署程序到模擬器上演示:

首先佈署"遠端服務" 到模擬器上,以下:

 

最小化 "遠程服務", 而後佈署" 調用遠程服務的方法"到模擬器上,以下:

接下咱們點擊  按鈕----綁定遠程服務 ,觀察logcat打印的日誌,以下:

這兩條日誌是 工程"遠程服務"中的RemoteServiceDemo中打印的;

 

咱們再點擊屢次這個  按鈕----調用遠程服務的方法  ,在觀察logcat打印的日誌,以下:

這兩條日誌是 工程"調用遠程服務的方法"中的MainActivity中call點擊事件,調用工程「遠程服務」中RemoteServiceDemo的methodInservice()方法打印的;以下:

 

 

4、使用 AIDL 遠程服務綁定調用的步驟

 (1採用bind的方法綁定開啓服務。

  Intent intent = new Intent();//隱式的意圖

      intent.setAction("action");
  bindService(intent, conn, BIND_AUTO_CREATE);

 (2)  .java的接口文件改爲.aidl文件,刪除public 訪問修飾符。

 3 在工程目錄gen目錄下會自動編譯生成IService.java的接口文件

      生成的IService.java,是經過aidl文件生成的。服務的中間人想暴露什麼方法,就怎麼定義接口

 4  遠程服務代碼爲private class MyBinder extends  IService.Stub

       同時在返回代理人對象,以下:

       public IBinder onBind(Intent intent){……}  

 5)實現ServiceConnection接口裏面的方法

  private class MyConn implements ServiceConnection{
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      IService.Sub.asInterface(service);
      System.out.println("Activity,獲得代理人對象");
    }

  注意:iService = IService.Stub.asInterface(service)

 6  iService.callMethodInService();

相關文章
相關標籤/搜索