Android中使用AIDL接口实现进程间通信
来源:互联网 发布:大数据解决方案 ppt 编辑:程序博客网 时间:2024/06/04 19:43
AIDL接口可以实现进程间通信,现在这个项目中也使用到了,activity通过AIDL接口调用下层MainService的方法。现在自己又研究了一把,今天把用法和其中的原理记录下来。
使用AIDL接口
实现一个从activity传值给service的功能,activity和service要在不同进程。android studio新建project就有了MainActivity,然后创建一个AIDL文件,这是一个接口,要在其中申明方法:
IMyAidlInterface.aidl
// IMyAidlInterface.aidlpackage acxingyun.cetcs.com.binder;// Declare any non-default types here with import statementsinterface IMyAidlInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int a);}
参数a就是要传的值。下面build一下project,然后新建service,创建一个AIDL.stub类:
MyService1.java
public class MyService1 extends Service { private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() { @Override public void basicTypes(int a) throws RemoteException { Log.i("MyService1", "basicTypes called,a:" + a); } }; public MyService1() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return iMyAidlInterface; } @Override public void onCreate() { Log.i(getClass().getSimpleName(), "onCreate..."); super.onCreate(); }}
在onBind中返回AIDL.stub给activity,activity通过bindservice得到AIDL.stub:
MainActivity.java
public class MainActivity extends AppCompatActivity { private final String TAG = getClass().getSimpleName(); private Button bt1; private Button bt2; private IMyAidlInterface iMyAidlInterface; private static final ComponentName SERVICE_COMPONENT = new ComponentName( "acxingyun.cetcs.com.binder", "acxingyun.cetcs.com.binder.MyService1"); private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("MainActivity", "onServiceConnected..."); iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt1 = (Button) findViewById(R.id.bt1); bt2 = (Button) findViewById(R.id.bt2); bt1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.i("MainActivity", "bt1 clicked..."); Intent intent = new Intent(); intent.setComponent(SERVICE_COMPONENT); bindService(intent, serviceConnection, BIND_AUTO_CREATE); } }); bt2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.i("MainActivity", "bt2 clicked..."); if (iMyAidlInterface != null){ try { iMyAidlInterface.basicTypes(100); } catch (RemoteException e) { e.printStackTrace(); } } } }); }}
由于service和activity要在不同进程,在manifest中配置service:
<service android:name=".MyService1" android:enabled="true" android:exported="true" android:process=":MyService" />
点击button1:
06-05 05:15:43.913 2630-2630/acxingyun.cetcs.com.binder I/MainActivity: bt1 clicked...06-05 05:15:43.942 1018-1508/system_process I/ActivityManager: Start proc 2654:acxingyun.cetcs.com.binder:MyService/u0a72 for service acxingyun.cetcs.com.binder/.MyService106-05 05:15:43.977 2654-2654/acxingyun.cetcs.com.binder:MyService I/MyService1: onCreate...06-05 05:15:43.978 2630-2630/acxingyun.cetcs.com.binder I/MainActivity: onServiceConnected...
MainActivity和service在不同进程,点击bt2调用aidl接口:
06-05 05:18:46.332 2630-2630/acxingyun.cetcs.com.binder I/MainActivity: bt2 clicked...06-05 05:18:46.333 2654-2670/acxingyun.cetcs.com.binder:MyService I/MyService1: basicTypes called,a:100
service得到了activity传的参数。
AIDL通信原理浅析
service端是一个AIDL.stub类:
private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() { @Override public void basicTypes(int a) throws RemoteException { Log.i("MyService1", "basicTypes called,a:" + a); } };
这个stub类通过onBind返回:
@Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return iMyAidlInterface; }
发现stub实际上是一个IBinder对象,activity端得到之后做了转换:
private IMyAidlInterface iMyAidlInterface; private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("MainActivity", "onServiceConnected..."); iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } };
通过IMyAidlInterface.Stub.asInterface(service)变成了之前定义的AIDL接口,于是通过这个AIDL接口就可以调用service端的方法:
iMyAidlInterface.basicTypes(100);
build工程后会自动生成一个IMyAidlInterface.java文件,里面包含了activity端和service端数据传递的代码,先贴出来慢慢说:
public interface IMyAidlInterface extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements acxingyun.cetcs.com.binder.IMyAidlInterface{private static final java.lang.String DESCRIPTOR = "acxingyun.cetcs.com.binder.IMyAidlInterface";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an acxingyun.cetcs.com.binder.IMyAidlInterface interface, * generating a proxy if needed. */public static acxingyun.cetcs.com.binder.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof acxingyun.cetcs.com.binder.IMyAidlInterface))) {return ((acxingyun.cetcs.com.binder.IMyAidlInterface)iin);}return new acxingyun.cetcs.com.binder.IMyAidlInterface.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_basicTypes:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();this.basicTypes(_arg0);reply.writeNoException();return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements acxingyun.cetcs.com.binder.IMyAidlInterface{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;}/** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */@Override public void basicTypes(int a) 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.writeInt(a);mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}}static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);}/** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */public void basicTypes(int a) throws android.os.RemoteException;}
这排版看的蛋疼,大致梳理下,最外层是aidl接口,申明了一个方法basicTypes(int a),stub是aidl的一个内部类,继承Binder实现了aidl接口,因此可以以IBinder形式返回给activity,它包含了三个方法:asInterface(),asBinder(),onTransact(),stub还有一个内部类Proxy。先从service创建开始,定义了一个stub对象:
private IMyAidlInterface.Stub iMyAidlInterface = new IMyAidlInterface.Stub() { @Override public void basicTypes(int a) throws RemoteException { Log.i("MyService1", "basicTypes called,a:" + a); } };
stub类要在service端实现aidl接口的方法。在onBind()中返回:
@Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return iMyAidlInterface; }
activity中得到stub对象并转换成aidl对象:
private IMyAidlInterface iMyAidlInterface; private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i("MainActivity", "onServiceConnected..."); iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } };
用到了IMyAidlInterface.Stub.asInterface(service),回到源码中:
public static acxingyun.cetcs.com.binder.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof acxingyun.cetcs.com.binder.IMyAidlInterface))) {return ((acxingyun.cetcs.com.binder.IMyAidlInterface)iin);}return new acxingyun.cetcs.com.binder.IMyAidlInterface.Stub.Proxy(obj);}
iin是调用IBinder.queryLocalInterface()得到的:
public IInterface queryLocalInterface(String descriptor) { if (mDescriptor.equals(descriptor)) { return mOwner; } return null; }
queryLocalInterface结果又和 mDescriptor有关,mDescriptor是在stub的构造函数中赋值:
private static final java.lang.String DESCRIPTOR = "acxingyun.cetcs.com.binder.IMyAidlInterface";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}
进去看:
public void attachInterface(IInterface owner, String descriptor) { mOwner = owner; mDescriptor = descriptor; }
传进去的descriptor和mDescriptor 都是一样的,关键是queryLocalInterface返回的对象mOwner,是stub类的this,也就是stub对象,不是一个IMyAidlInterface实例,所以最后会返回:
acxingyun.cetcs.com.binder.IMyAidlInterface.Stub.Proxy(obj);
Proxy(obj)是一个proxy类:
private static class Proxy implements acxingyun.cetcs.com.binder.IMyAidlInterface{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;}/** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */@Override public void basicTypes(int a) 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.writeInt(a);mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}}
activity调用aidl方法也就是在proxy类中调用aidl的方法basicTypes(),由于obj实际上是aidl.stub对象,也就是把service传来的stub对象给了mRemote,mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0),就是stub.transact()方法,就是Binder.transact(),里面又会调用Binder.onTransact(),而Binder.onTransact()又在stub继承Binder的时候被override了:
@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_basicTypes:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();this.basicTypes(_arg0);reply.writeNoException();return true;}}return super.onTransact(code, data, reply, flags);}
于是,根据传的参数code,进入case TRANSACTION_basicTypes,调用this.basicTypes(_arg0),也就是当前IMyAidlInterface.java申明的方法basicTypes(int a),实现又是在service中,最后实现了activity对service方法的调用。
阅读全文
0 0
- Android中使用AIDL接口实现进程间通信
- android 中使用aidl实现进程间通信
- android 使用AIDL实现进程间通信
- Android使用AIDL实现进程间通信
- Android使用AIDL实现进程间通信
- Android使用AIDL实现进程间通信
- Android使用AIDL实现进程间通信
- Android使用AIDL实现进程间通信
- Android使用AIDL实现进程间通信
- Android中AIDL使用 及 AIDL实现进程间的通信
- Android实现进程间通信aidl的使用
- android使用aidl实现进程间通信的实例
- Android基础--使用AIDL实现进程间的通信
- Android AIDL使用详解 实现进程间的通信
- Android Studio使用AIDL 实现进程间通信实例
- 学习笔记 Android 使用AIDL实现进程间通信
- Android:不使用AIDL实现进程间的通信
- android使用AIDL实现进程间的通信
- java如何获取window 客户端的登录用户名称
- Andriod studio——布局
- 高级JAVA码农不一定都搞清楚了它们的区别
- wubi安装Ubuntu后扩充Ubuntu系统空间
- 倒水C++小程序
- Android中使用AIDL接口实现进程间通信
- 信号量sem_t,互斥锁pthread_mutex_t的使用
- Android图像处理_底片效果
- 关于Java的File.separator
- Android错误提示信息: java.lang.StackOverflowError: stack size 8MB
- iOS取CGFloat的小数点后2位
- 网站一直排名在100名之外的原因
- STL之vector向量容器常用方法
- JSF表达式语言