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();

相关文章
相关标签/搜索