Android IPC 之 AIDL(一)
来源:互联网 发布:遗传算法 排课系统 编辑:程序博客网 时间:2024/05/16 05:50
IPC是Inter-Process Communication的缩写,即跨进程通信。Android中跨进程通信有多种方式,如文件共享、使用ContentProvider、Broadcast、和Socket等。比较复杂的情况下,常用的两种方式为Messenger和AIDL,而Messenger的底层实现又是AIDL。
首先不看别的,先来看一下AIDL是如何使用的。
假设我们现在有一个两数相加的任务,客户端没办法完成(别问我它为什么完不成==,咱举栗子简单点哈~),需要将任务交给另一个进程中的服务端完成,再从服务端获取到该任务的结果。
我们首先如下图方式创建一个AIDL接口:
Android Studio会自动为它生成一个路径,如下图:
在该文件中声明一个接口以及一个我们想让服务端实现的接口方法。如下:
package com.vera.aidltest;interface IMyAdd { int myAdd(int num_a,int num_b);}
注意,并不是所有数据类型都能在AIDL文件中使用,AIDL文件只支持以下几种数据类型:
- Java 中的基本数据类型
- String 和CharSequence
- List 和 Map ,且List和Map 对象的元素必须是AIDL支持的数据类型
- AIDL 自动生成的接口 ,需要导入(import,即使同处于一个包中)
- 实现android.os.Parcelable 接口的类的对象. 需要导入(import,即使同处于一个包中),且必须新建一个与其同名的AIDL文件,并在文件中声明该类为Parcelable
在接口定义好后,系统将为我们生成一个Java文件,AS下是在app\build\generated\source\aidl\debug目录下,生成的代码如下:
package com.vera.aidltest;public interface IMyAdd extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.vera.aidltest.IMyAdd{private static final java.lang.String DESCRIPTOR = "com.vera.aidltest.IMyAdd";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an com.vera.aidltest.IMyAdd interface, * generating a proxy if needed. */public static com.vera.aidltest.IMyAdd asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.vera.aidltest.IMyAdd))) {return ((com.vera.aidltest.IMyAdd)iin);}return new com.vera.aidltest.IMyAdd.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_myAdd:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int _result = this.myAdd(_arg0, _arg1);reply.writeNoException();reply.writeInt(_result);return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.vera.aidltest.IMyAdd{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 myAdd(int num_a, int num_b) 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);_data.writeInt(num_a);_data.writeInt(num_b);mRemote.transact(Stub.TRANSACTION_myAdd, _data, _reply, 0);_reply.readException();_result = _reply.readInt();}finally {_reply.recycle();_data.recycle();}return _result;}}static final int TRANSACTION_myAdd = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);}public int myAdd(int num_a, int num_b) throws android.os.RemoteException;}
代码很长很凌乱的样子……嗯,本节我们先不看它,只需要知道它是根据AIDL文件生成的一个接口IMyAdd,包含一个继承自Binder的静态内部抽象类Stub(咦,这么连起来说总有哪里怪怪的……),并且声明了myAdd()方法。为什么是抽象类呢,因为它实现了IMyAdd接口却并没有真正实现,那放到哪里实现呢?当然是我们的服务端咯。
接下来,我们可以就可以来写客户端和服务端的代码了,那么,我们这里的客户端和服务端指的是什么呢?就本例来说,它们分别是一个Activity和一个Service,这里我们将它们放在了同一个应用中,只不过通过某种方法使其运行在不同的进程。更多情况下它们并不运行在同一个应用中,这时候我们需要将整个aidl文件夹的内容复制一份,这是因为客户端和服务端的AIDL包结构需要保持一致,否则将会出现反序列化不成功的结果,那么跨进程通信将无法进行。
那么我们现在开始写服务端的代码,新建一个Service名为ServerService如下:
package com.vera.aidltest;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;public class ServerService extends Service { private Binder mBinder=new IMyAdd.Stub(){ @Override public int myAdd(int num_a, int num_b) throws RemoteException { int result=num_a+num_b; Log.d("ServerService","the result of "+num_a+" and "+num_b+" is "+result); return result; } }; @Override public IBinder onBind(Intent intent) { return mBinder; }}
ServerService很简单,它只是创建了一个Binder对象并在onBinder()方法中将其返回。该Binder对象就是我们实现了接口方法的Stub对象。好啦,现在我们可以在myAdd()方法中愉快地进行我们的操作啦。在这里我们只是得到num_a和num_b的和并将其打印,最后再返回结果。
另外,我们需要将该Service设置在一个独立的进程中,不然还怎么玩跨进程通信~
更改AndroidManifest.xml如下:
<service android:name=".ServerService" android:process=":remote"></service>
好了,服务端的创建已经完成啦,我们现在来看客户端。客户端要做些什么呢?,我们来看代码:
package com.vera.aidltest;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.Button;public class ClientActivity extends AppCompatActivity { Button mButton; private ServiceConnection myConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { IMyAdd mMyAdd=IMyAdd.Stub.asInterface(iBinder); try { int result=mMyAdd.myAdd(1,2); Log.d("ClientActivity","get the result is "+result); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); mButton=(Button)findViewById(R.id.activity_client_mbutton); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent=new Intent(ClientActivity.this,ServerService.class); bindService(intent,myConnection, Context.BIND_AUTO_CREATE); } }); } @Override protected void onDestroy(){ unbindService(myConnection); super.onDestroy(); }}
首先,我们创建了一个ServiceConnection的匿名类并实例化一个对象,然后,我们又设置了在Button点击之后通过bindService()方法绑定服务。bindService()方法接收三个参数,第一个是在这之前我们创建的Intent对象,第二个是ServiceConnection的实例对象,第三个参数是一个标志位,BIND_AUTO_CREATE表示在Activity和Service进行绑定后,服务将自动创建。然后我们重写了onDestroy()方法,将Activity和Service解除绑定。
重点是在创建的ServiceConnection匿名类里!在这个类里我们重写了onServiceConnected()方法和onServiceDisconnected()方法,这两个方法分别会在Activity与Service成功绑定和解除绑定的时候调用。在onServiceConnected()方法里,我们调用了Stub()的asInterface()方法,该方法返回一个Binder代理对象,并向上转型成为客户端接受的AIDL接口类型的对象!
好啦,拿到了这个对象,现在只差一步调用方法的事啦,我们来试一试1+2等于多少叭~
运行程序,在点击Button之后,查看日志打印信息,如下图:
在com.vera.aidltest进程中,客户端打印出得到的结果为3,在com.vera.aidltest:remote进程中,服务端打印出1+2等于3(我英语不好……),通信成功啦!
嗯好,那我们来总结一下,具体的步骤吧:
- 首先建立一个AIDL文件,在其中定义一个接口,接口中应包含我们希望服务端实现的方法的声明。
- 其次,在服务端中将实现好方法的Stub对象通过onBind()方法返回
- 最后,在客户端中将服务绑定,并重写ServiceConnection类中的方法,在其中获得Binder对象,调用服务端的接口方法。
这其中我们屏蔽了很多细节,只谈了使用方法,下一节婷子会把更具体的部分再贴出来,第一篇技术博客,有什么不对的地方还请留言哦,么么哒~
- Android IPC 之 AIDL(一)
- Android之使用AIDL进行IPC(一)
- Android IPC之AIDL
- Android IPC 之AIDL
- Android IPC之AIDL
- Android IPC 之 AIDL
- Android IPC之AIDL
- Android IPC 之 AIDL (二)
- Android IPC之AIDL浅谈
- android IPC机制之 AIDL
- 安卓IPC之aidl使用(一)--aidl常见使用
- android进程间通信(IPC)之AIDL
- 【Android机制】IPC机制之AIDL
- Android进程间通信(IPC)之AIDL
- Android IPC机制之AIDL的使用
- Android IPC之AIDL使用解析
- Android IPC之AIDL的使用
- Android IPC通信之AIDL理解
- Java Socket 编程 Socket与ServerSocket
- CodeForces 546B
- 《C++》05 C++ 修饰符类型
- python(1)-简单数据类型
- (二)BeautifulSoup的基本了解使用
- Android IPC 之 AIDL(一)
- 阿里云美国服务器上架设VPN/代理不能访问facebook TW
- 字典转模型之KVC和MJExtension底层实现
- iOS中几种数据持久化方案-转自简书
- HDOJ-----1060简单数学题
- 《C++》06 C++ 存储类
- HDU 5651
- CRCK array 1.5 (easy)
- Linux 每天定时重启