Android中AIDL实现进程通信.doc_第1页
Android中AIDL实现进程通信.doc_第2页
Android中AIDL实现进程通信.doc_第3页
Android中AIDL实现进程通信.doc_第4页
Android中AIDL实现进程通信.doc_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Android中AIDL实现进程通信之前的文章演示了如何通过Messenger实现与Service进行跨进程通信,即IPC。但用Messenger实现的IPC存在一点不足:Service内部维护着一个Messenger,Messenger内部又维护着一个Hanlder,当多个client向该Service发送Message时,这些Message需要依次进入Hanlder的消息队列中,Hanlder只能处理完一个Message之后,再从消息队列中取出下一个进行处理,这样Service相当于只能对客户端传来的Message进行串行执行,而不能并行执行。如果想让Service跨进程并发处理客户端发来的请求,那么就需要使用AIDL。AIDL的全称是Android Interface Definition Language,直译过来就是Android接口定义语言。在Android中,正常情况下,不同进程是不能互相访问对方的内存数据的。为了实现进程间内存访问,可以将一个进程中的内存数据分解成Android认识的原子类型,然后在另一个进程中将原子类型的数据重新组合成对象。编写将原子类型的数据重新组合成对象的代码比较费时,Android通过AIDL可以实现该功能。其实Messenger和AIDL并不是对立的,Messenger内部也是基于AIDL实现的。当使用Messenger的时候,Service会用一个Handler串行执行客户端发来的多个请求,即单线程处理;当直接使用AIDL的时候,Service会维护一个线程池,用该线程池并发处理客户端发来的多个请求。再次强调一下,如果你想实现跨进程通信,但是并不关注多线程并发处理,那么你只需要使用Messenger即可,无需编写AIDL代码,只有当你想让Service并发处理客户端的请求的时候,才需要编写AIDL代码。AIDL之Service端实现使用AIDL的典型案例就是一个App的Activity启动了一个Service,并且让该Service运行在一个新的进程中,这种在新进程中的Service我们可以叫做远程Service,该Service会从服务器拿到最新的数据,客户端可以调用Service相应的方法获得最新数据,更近一步的话,Service拿到最新数据之后可以主动向客户端发送。要想使用AIDL,要同时在Service和client都编写相应的代码。在Service端,首先要创建.aidl文件,然后需要实现.aidl中定义的各种方法。具体如下:首先要创建.aidl文件在Android Studio中右键创建AIDL文件,该文件其实就是定义一个接口Interface,和定义一般的Java接口差不多,需要在该接口中定义一些方法,这些方法就是允许客户端跨进程调用的方法,我创建了IRemoteService.aidl文件,如下所示:/ IRemoteInterface.aidlpackage com.ispring.aidldemo;import com.ispring.aidldemo.IRemoteInterfaceCallback;interface IRemoteInterface /获取Service运行的进程ID int getPid(); /从Service中获取最新的数据 int getData(); /通过向Service中注册回调,可以实现Service主动向客户端推送数据 void registerCallback(IRemoteInterfaceCallback cb); /删除注册的回调 void unregisterCallback(IRemoteInterfaceCallback cb);我们在上面的.aidl文件中,定义了四个方法供客户端调用,通过getPid()方法,可以获取Service运行的进程ID;通过getData()方法,可以让客户端从Service获取最新的数据;registerCallback和unregisterCallback是用来进行注册、反注册客户端回调的,后面会详细解释。AIDL中定义的方法可以接受如下的参数类型作为形参:所有的基本类型,例如int, long, char, boolean等等String、CharSequence、List、Map在编写完上述IRemoteInterface.aidl文件后,我们编译一下Project,Android Studio会自动帮我们生成一个IRemoteInterface.java文件,如下所示(对于下面的代码,我们无需关注具体实现,大家了解一下即可):/* * This file is auto-generated. DO NOT MODIFY. * Original file: D:iWorkAndroidStudioProjectsAidlDemoappsrcmainaidlcomispringaidldemoIRemoteInterface.aidl */package com.ispring.aidldemo;public interface IRemoteInterface extends android.os.IInterface /* Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.ispring.aidldemo.IRemoteInterface private static final java.lang.String DESCRIPTOR = com.ispring.aidldemo.IRemoteInterface; /* Construct the stub at attach it to the interface. */ public Stub() this.attachInterface(this, DESCRIPTOR); /* * Cast an IBinder object into an com.ispring.aidldemo.IRemoteInterface interface, * generating a proxy if needed. */ public static com.ispring.aidldemo.IRemoteInterface asInterface(android.os.IBinder obj) if (obj=null) return null; android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (iin!=null)&(iin instanceof com.ispring.aidldemo.IRemoteInterface) return (com.ispring.aidldemo.IRemoteInterface)iin); return new com.ispring.aidldemo.IRemoteInterface.Stub.Proxy(obj); Override public android.os.IBinder asBinder() return this; Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException switch (code) case INTERFACE_TRANSACTION: reply.writeString(DESCRIPTOR); return true; case TRANSACTION_getPid: data.enforceInterface(DESCRIPTOR); int _result = this.getPid(); reply.writeNoException(); reply.writeInt(_result); return true; case TRANSACTION_getData: data.enforceInterface(DESCRIPTOR); int _result = this.getData(); reply.writeNoException(); reply.writeInt(_result); return true; case TRANSACTION_registerCallback: data.enforceInterface(DESCRIPTOR); com.ispring.aidldemo.IRemoteInterfaceCallback _arg0; _arg0 = com.ispring.aidldemo.IRemoteInterfaceCallback.Stub.asInterface(data.readStrongBinder(); this.registerCallback(_arg0); reply.writeNoException(); return true; case TRANSACTION_unregisterCallback: data.enforceInterface(DESCRIPTOR); com.ispring.aidldemo.IRemoteInterfaceCallback _arg0; _arg0 = com.ispring.aidldemo.IRemoteInterfaceCallback.Stub.asInterface(data.readStrongBinder(); this.unregisterCallback(_arg0); reply.writeNoException(); return true; return super.onTransact(code, data, reply, flags); private static class Proxy implements com.ispring.aidldemo.IRemoteInterface private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) mRemote = remote; Override public android.os.IBinder asBinder() return mRemote; public java.lang.String getInterfaceDescriptor() return DESCRIPTOR; Override public int getPid() throws android.os.RemoteException android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); finally _reply.recycle(); _data.recycle(); return _result; Override public int getData() throws android.os.RemoteException android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getData, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); finally _reply.recycle(); _data.recycle(); return _result; Override public void registerCallback(com.ispring.aidldemo.IRemoteInterfaceCallback cb) throws android.os.RemoteException android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder(cb!=null)?(cb.asBinder():(null); mRemote.transact(Stub.TRANSACTION_registerCallback, _data, _reply, 0); _reply.readException(); finally _reply.recycle(); _data.recycle(); Override public void unregisterCallback(com.ispring.aidldemo.IRemoteInterfaceCallback cb) throws android.os.RemoteException android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder(cb!=null)?(cb.asBinder():(null); mRemote.transact(Stub.TRANSACTION_unregisterCallback, _data, _reply, 0); _reply.readException(); finally _reply.recycle(); _data.recycle(); static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_getData = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_registerCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); static final int TRANSACTION_unregisterCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); public int getPid() throws android.os.RemoteException; public int getData() throws android.os.RemoteException; public void registerCallback(com.ispring.aidldemo.IRemoteInterfaceCallback cb) throws android.os.RemoteException; public void unregisterCallback(com.ispring.aidldemo.IRemoteInterfaceCallback cb) throws android.os.RemoteException;对于上面的代码,我们无需关注具体实现,我们只需要知道以下几点即可:IRemoteInterface.java中,定义了名为IRemoteInterface的interface,其对应着IRemoteInterface.aidl定义的接口,囊括了IRemoteInterface.aidl中定义的方法。IRemoteInterface继承自android.os.IInterface,如下所示:public interface IRemoteInterface extends android.os.IInterfaceIRemoteInterface接口中有一个静态内部类Stub。Stub是个抽象类,继承自android.os.Binder,且实现了IRemoteInterface接口,如下所示:public static abstract class Stub extends android.os.Binder implements com.ispring.aidldemo.IRemoteInterfaceSub类中有一个asInterface方法,该方法非常重要,其接收一个android.os.IBinder类型的对象,返回IRemoteInterface类型,其方法签名如下定义:public static com.ispring.aidldemo.IRemoteInterface asInterface(android.os.IBinder obj)实现AIDL所定义的接口我们定义了一个RemoteService类,其继承自Service,该类表示客户端要调用的远程服务,我们在AndroidManifest.xml文件中对该Service进行如下配置:我们通过android:process=:remote,让Service运行在一个新的进程中,而不是原有App的进程,其新进程的名字是remote,当然也可以是其他的名称。remote前面的冒号表示该进程被当前的App独享,是该App的私有进程;如果去掉remote前面的冒号,那么则表示该进程是被多个App所共享的。RemoteService源码如下所示:package com.ispring.aidldemo;import android.app.Service;import android.content.Intent;import android.os.*;import android.util.Log;import java.util.Random;public class RemoteService extends Service private Random random = new Random(); /callbacks存储了所有注册过的客户端回调 private final RemoteCallbackList callbacks = new RemoteCallbackList(); private static final int MSG_REPORT_DATA = 0; /该handler用来每隔一秒主动向所有注册过回调的客户端发送信息 private Handler handler = new Handler() Override public void handleMessage(Message msg) switch (msg.what) case MSG_REPORT_DATA: /开始广播,获取客户端的数量 final int n = callbacks.beginBroadcast(); int data = random.nextInt(100); for(int i = 0; i callback.dataChanged(data), PID= + android.os.Process.myPid() + , Thread= + Thread.currentThread().getName(); callback.dataChanged(data); catch (RemoteException e) e.printStackTrace(); /结束广播 callbacks.finishBroadcast(); /构建新的Message,延迟1秒发送,这样handler每隔一秒都会受到Message Message pendingMsg = obtainMessage(MSG_REPORT_DATA); sendMessageDelayed(pendingMsg, 1000); break; default: super.handleMessage(msg); ; /我们要实现 IRemoteInterface.Stub binder = new IRemoteInterface.Stub() Override public int getPid() throws RemoteException return android.os.Process.myPid(); Override public int getData() throws RemoteException Log.i(DemoLog, RemoteService: binder - getData, PID= + android.os.Process.myPid() + , Thread= + Thread.currentThread().getName(); return random.nextInt(100); Override public void registerCallback(IRemoteInterfaceCallback cb) throws RemoteException Log.i(DemoLog, RemoteService: binder - registerCallback, PID= + android.os.Process.myPid() + , Thread= + Thread.currentThread().getName(); if(cb != null) /注册客户端回调 callbacks.register(cb); Override public void unregisterCallback(IRemoteInterfaceCallback cb) throws RemoteException Log.i(DemoLog, RemoteService: binder - unregisterCallback, PID= + android.os.Process.myPid() + , Thread= + Thread.currentThread().getName(); if(cb != null) /反注册客户端回调 callbacks.unregister(cb); ; public RemoteService() Override public void onCreate() super.onCreate(); handler.sendEmptyMessage(MSG_REPORT_DATA); Log.i(DemoLog, RemoteService - onCreate, PID= + android.os.Process.myPid() + , Thread= + Thread.currentThread().getName(); Override public IBinder onBind(Intent intent) return binder; Override public void onDestroy() Log.i(DemoLog, RemoteService - onDestroy, PID= + android.os.Process.myPid() + , Thread= + Thread.currentThread().getName(); /反注册所有的客户端回调,并且不再接收新的客户端回调 callbacks.kill(); /移除pedding message,停止message循环,防止内存泄露 handler.removeMessages(MSG_REPORT_DATA); super.onDestroy(); 我们对上述部分代码进行说明:首先我们通过IRemoteInterface.Stub binder = new IRemoteInterface.Stub()实例化了一个IRemoteInterface.Stub对象。之前我们提到IRemoteInterface.Stub继承自android.os.Binder,所以该实例也就是一个Binder,并且其实现了接口IRemoteInterface定义的抽象方法。然后在Service的onBind接口中将上述binder对象返回,这样才能让客户端通过bindService方法调用Service。我们在后面会解释handler、客户端回调相关的代码片段。AIDL之客户端实现通常调用Service的客户端是Activity,我在MainActivity中调用RemoteService,其界面如下所示:客户端MainActivity源码如下所示:package com.ispring.aidldemo;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.*;import android.app.Activity;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity implements Button.OnClickListener private Button btnBindService; private Button btnGetData; private Button btnRegister; private Button btnUnregister; private Button btnUnbindService; private Button btnKillProcess; private TextView textView; private boolean isRegistered = false; private IRemoteInterface remoteInterface; private static final int MSG_GET_DATA = 0; private static final int MSG_DATA_CHANGED = 1; /handler用于在主线程中更新UI private Handler handler = new Handler() Override public void handleMessage(Message msg) switch (msg.what) case MSG_GET_DATA: /通过远程服务的getData方法获取数据 Toast.makeText(MainActivity.this, Data: + msg.arg1, Toast.LENGTH_LONG).show(); break; case MSG_DATA_CHANGED: /远程服务通过客户端回调向客户端推送数据 textView.setText(Receive data from service: + msg.arg1); break; default: super.handleMessage(msg); ; private ServiceConnection sc = new ServiceConnection() Override public void onServiceConnected(ComponentName name, IBinder binder) Log.i(DemoLog, MainActivity: ServiceConnection - onServiceConnected); remoteInterface = IRemoteInterface.Stub.asInterface(binder); /更新UI状态 btnBindService.setEnabled(false); btnGetData.setEnabled(true); btnRegister.setEnabled(true); btnUnregister.setEnabled(false); btnUnbindService.setEnabled(true); btnKillProcess.setEnabled(true); textView.setText(已连接到RemoteService); Override public void onServiceDisconnected(ComponentName name) Log.i(DemoLog, MainActivity: ServiceConnection - onServiceDisconnected); remoteInterface = null; /更新UI状态 btnBindService.setEnabled(true); btnGetData.setEnabled(false); btnRegister.setEnabled(false); btnUnregister.setEnabled(f

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论