Android进阶笔记:AIDL内部实现详解 (二)
2016-01-17 15:52
555 查看
接着上一篇分析的aidl的流程解析。知道了aidl主要就是利用Ibinder来实现跨进程通信的。既然是通过对Binder各种方法的封装,那也可以不使用aidl自己通过Binder来实现跨进程通讯。那么这篇博客就主要就写一下通过上篇(Android进阶笔记:AIDL详解(一))总结的知识来自己实现跨进程通讯从而更加透彻的了解aidl的核心逻辑。
首先上一篇博客(Android进阶笔记:AIDL详解(一))中总结出一个结论————“onTransact方法是提供给server端用的,transact方法(内部类proxy封装了transact方法)和asInterface方法是给client端用的。”因此很清楚,只要我们在Server端实现跨进程需要调用的方法(类似aidl的接口实现)和onTransact方法,而服务端只要通过获得的IBinder对象来调用transact方法就可以代替aidl来实现跨进程通讯了。既然思路已经整理清楚了,那就一步一步来实现它。
MyBinder.java
代码非常简单,只是重新写了一下onTransact方法。其实一共只有4步:
根据code的值来判断client端具体想要调用哪个方法;
读取parcel对象(data)中传入的参数;
调用自己本地的方法(add)并将参数传入;
把结果写入parcel对象(reply)中;
接着只要把这个自己定义的MyBinder类的实例通过Service.onBInder方法返回给Client端就可以了。
MyService.java
WithoutAidlActivity.java
首先连接成功后在serviceConnection.onServiceConnected方法中获得了IBinder实例,然后总共做了3个事情:
创建两个parcel对象分别存放参数(data)和返回值(reply)
调用transact方法,传入data,reply,和你要调用的方法code。最后的flag传入0表示有返回值(1表示没有又返回值)
从reply中获得结果
完成以上工作就可以不通过aidl实现跨进程通讯了。但是还是要说一下,这里我们server端调用的只是一个简单的add方法不耗时的,而transact方法则是在onServiceConnected方法中被调用的其实是在主线程中执行的。如果add方法换成一个耗时方法,那么主线程(UI线程)是会卡死的,调用transact方法时当前线程会被挂起知道结果被返回(有兴趣可以去试试,只要在add方法里面加一个Thread.sleep就可以了)。所以最好的办法就是起一个线程来调用transact方法。
首先上一篇博客(Android进阶笔记:AIDL详解(一))中总结出一个结论————“onTransact方法是提供给server端用的,transact方法(内部类proxy封装了transact方法)和asInterface方法是给client端用的。”因此很清楚,只要我们在Server端实现跨进程需要调用的方法(类似aidl的接口实现)和onTransact方法,而服务端只要通过获得的IBinder对象来调用transact方法就可以代替aidl来实现跨进程通讯了。既然思路已经整理清楚了,那就一步一步来实现它。
Server端
首先Server端是要通过Service的onBind方法来给Client端一个Binder对象,那就先从这个Binder对象入手。那就先来创建了一个MyBinder类,代码如下:MyBinder.java
public class MyBinder extends Binder { //标记方法的 private static final int METHOD_ADD_CODE = 1001; //标识binder对象的 private static final String DESCRIPTION = "not use aidl"; @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (code == METHOD_ADD_CODE) { //验证一下binder data.enforceInterface(DESCRIPTION); //从parcel对象中读取参数 int arg0 = data.readInt(); int arg1 = data.readInt(); //写入结果 reply.writeInt(add(arg0, arg1)); return true; } return super.onTransact(code, data, reply, flags); } private int add(int arg0, int arg1) { return arg0 + arg1; } }
代码非常简单,只是重新写了一下onTransact方法。其实一共只有4步:
根据code的值来判断client端具体想要调用哪个方法;
读取parcel对象(data)中传入的参数;
调用自己本地的方法(add)并将参数传入;
把结果写入parcel对象(reply)中;
接着只要把这个自己定义的MyBinder类的实例通过Service.onBInder方法返回给Client端就可以了。
MyService.java
public class MyService extends Service { private MyBinder myBinder; public MyService() { } @Override public void onCreate() { super.onCreate(); //创建实例 myBinder = new MyBinder(); } @Override public IBinder onBind(Intent intent) { //返回自定义的binder对象 return myBinder; } }
Client端
client端的代码无非就是把之前写在aidl中的proxy内部类的方法拿出来了。具体看代码:WithoutAidlActivity.java
public class WithoutAidlActivity extends AppCompatActivity { private ServiceConnection serviceConnection; private IBinder binder; //以下两个参数要和server端保持一致 //标记方法的(告知server端调用哪个方法) private static final int METHOD_ADD_CODE = 1001; //标识binder对象的 private static final String DESCRIPTION = "not use aidl"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_without_aidl); serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d("onServiceConnected", "onServiceConnected: connected success!"); binder = service; //这里就代替aidl中的proxy来直接调用transact方法 //先准备参数 Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(DESCRIPTIO 4000 N); data.writeInt(123); data.writeInt(456); try { //调用transact方法 binder.transact(METHOD_ADD_CODE, data, reply, 0); //获得结果 int result = reply.readInt(); Log.d("onServiceConnected", "result = " + result); } catch (RemoteException e) { e.printStackTrace(); } finally { data.recycle(); reply.recycle(); } } @Override public void onServiceDisconnected(ComponentName name) { binder = null; } }; bindService(new Intent("com.coder_f.aidlserver.MyService"), serviceConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(serviceConnection); } }
首先连接成功后在serviceConnection.onServiceConnected方法中获得了IBinder实例,然后总共做了3个事情:
创建两个parcel对象分别存放参数(data)和返回值(reply)
调用transact方法,传入data,reply,和你要调用的方法code。最后的flag传入0表示有返回值(1表示没有又返回值)
从reply中获得结果
完成以上工作就可以不通过aidl实现跨进程通讯了。但是还是要说一下,这里我们server端调用的只是一个简单的add方法不耗时的,而transact方法则是在onServiceConnected方法中被调用的其实是在主线程中执行的。如果add方法换成一个耗时方法,那么主线程(UI线程)是会卡死的,调用transact方法时当前线程会被挂起知道结果被返回(有兴趣可以去试试,只要在add方法里面加一个Thread.sleep就可以了)。所以最好的办法就是起一个线程来调用transact方法。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories