Android IPC 之AIDL
2016-01-17 12:00
447 查看
这几天深圳阴雨绵绵,让一个宅男连出去的欲望都没了。
看看效果图吧:
以打印log的方式出来的:
其中自定义的parcelable对象和aidl对象必须要显示import进来,不管是否在同一个包中。
并且如果使用了book这个类,必须要新建一个同名的aidl文件,声明为parcelable类型。
不然Android studio中会报:
java.lang.runtimeExcepition: com.android.ide.common.process.processException:org.gradle.process.internal.execException:process ‘command ‘E:|androidsdk\sdk\build-toos\23.0.2\aidl.exe” finished with non-sero exit value 1
这个demo中我们使用了一个 IBookManager.aidl文件,然后其中内部还使用了一个Book类,当然这个Book类必须实现parcelable接口,这个aidl中需要新建一个Book.aidl文件,然后将这个Book声明为一个parcelable对象。
Book.aidl:
然后看看IBookManager.aidl中:
导入book,当然后面还使用了一个 IOnNewBookArrivedListener,用来做一个观察模式:
我们就看看
List getBookList();
void addBook(in Book book);
这两个方法
一个是客户端从服务端获取所有book,一个是客户端为服务端添加一本书的方法。
这两个方法运行在客户端,并且调用的时候当前的线程会挂起,然后直至方法运行至服务端运行完毕然后返回线程才继续运行,所以这两个方法如果运行在客户端的ui线程中的话那么是有anp(应用程序未响应)的危险的。所以最好还是另开一个线程去调用。
然后服务端的binder运行在binder线程池中,所以方法可以使用同步的方式,因为已经是运行在另个线程中了。
好现在我们新建一个Service,这个service需要是运行在另个进程中的。
我们先看看两个集合:
使用的CopyOnWriteArrayList来保存book,因为这个是自动的线程同步的。
RemoteCallbackList是用来专门保存进程的listener,因为用普通的ArrayList,或者CopyOnWriteArrayList,当客户端想去删除的某个listener的时候传入的listener和服务端的listener并不是同一个。所以删除会出现问题。但是为什么这个可以呢,因为用的底层binder直接使用的(因为底层的binder是同一个)。
然后看看我们实现IBookManager.aidl中的接口
就是实现了四个方法
注意listenerLists.beginBroadcast(); listenerLists.finishBroadcast();需要成对使用。
每次到了一本新书,就发送各个通知。
最后我们来看看客户端如何实现的,Activity的oncreate中进行BindService
获得IBookManager,然后远程调用各个方法,并且注册了一个通知。
在onDestory()中注销通知。注销的通知 iOnNewBookArrivedListener,和注册的通知是同一个,因为中间经历了一层binder,所以这个iOnNewBookArrivedListener不是服务端的iOnNewBookArrivedListener,所以服务端使用的 RemoteCallbackList来装。
刚睡醒。。。。。。。。。。无聊死了。。。。。要是深圳的童鞋们有谁想骑车玩的,拜托叫我一声啊。
源码下载
参考书籍《Android开发艺术探索》
加个好友共同学习(不是公众号):
因为小弟水平有限,如果有写的有问题,希望指出。
一:概述
上一篇写了下Messenger的如何使用,这篇写一下AIDL 如何使用,Messenger是一对多的串行使用,而AIDL是可以一对多的并发。看看效果图吧:
以打印log的方式出来的:
二:看看代码
在aidl中仅支持以下数据类型:[code]1.基本数据类型(int,long,char,boolean,byte等) 2.String 和 CharSequence; 3.List:只支持ArrayList,并且他其中的元素必须被aidl支持 4.Map:只支持HashMap,里面的每个元素也需要被支持 5.Parcelable:所有实现了这个接口的对象 6.aidl:所有的aidl接口本身也可以在aidl文件中使用
其中自定义的parcelable对象和aidl对象必须要显示import进来,不管是否在同一个包中。
并且如果使用了book这个类,必须要新建一个同名的aidl文件,声明为parcelable类型。
不然Android studio中会报:
java.lang.runtimeExcepition: com.android.ide.common.process.processException:org.gradle.process.internal.execException:process ‘command ‘E:|androidsdk\sdk\build-toos\23.0.2\aidl.exe” finished with non-sero exit value 1
这个demo中我们使用了一个 IBookManager.aidl文件,然后其中内部还使用了一个Book类,当然这个Book类必须实现parcelable接口,这个aidl中需要新建一个Book.aidl文件,然后将这个Book声明为一个parcelable对象。
Book.aidl:
然后看看IBookManager.aidl中:
导入book,当然后面还使用了一个 IOnNewBookArrivedListener,用来做一个观察模式:
我们就看看
List getBookList();
void addBook(in Book book);
这两个方法
一个是客户端从服务端获取所有book,一个是客户端为服务端添加一本书的方法。
这两个方法运行在客户端,并且调用的时候当前的线程会挂起,然后直至方法运行至服务端运行完毕然后返回线程才继续运行,所以这两个方法如果运行在客户端的ui线程中的话那么是有anp(应用程序未响应)的危险的。所以最好还是另开一个线程去调用。
然后服务端的binder运行在binder线程池中,所以方法可以使用同步的方式,因为已经是运行在另个线程中了。
好现在我们新建一个Service,这个service需要是运行在另个进程中的。
[code] <service android:name=".BookManagerService" android:enabled="true" android:exported="true" android:process=":remote" />
我们先看看两个集合:
[code] private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>(); private RemoteCallbackList<IOnNewBookArrivedListener> listenerLists = new RemoteCallbackList<IOnNewBookArrivedListener>();
使用的CopyOnWriteArrayList来保存book,因为这个是自动的线程同步的。
RemoteCallbackList是用来专门保存进程的listener,因为用普通的ArrayList,或者CopyOnWriteArrayList,当客户端想去删除的某个listener的时候传入的listener和服务端的listener并不是同一个。所以删除会出现问题。但是为什么这个可以呢,因为用的底层binder直接使用的(因为底层的binder是同一个)。
然后看看我们实现IBookManager.aidl中的接口
[code] private Binder mBinder = new IBookManager.Stub() { public List<Book> getBookList() { return mBookList; } public void addBook(Book book) { mBookList.add(book); } public void registerLintener(IOnNewBookArrivedListener lis) { listenerLists.register(lis); final int count = listenerLists.beginBroadcast(); Log.e("xhc", "listenerLists.size " + count); listenerLists.finishBroadcast(); } public void unregisterListener(IOnNewBookArrivedListener lis) { listenerLists.unregister(lis); final int count = listenerLists.beginBroadcast(); Log.e("xhc", "listenerLists.size " + count); listenerLists.finishBroadcast(); } };
就是实现了四个方法
注意listenerLists.beginBroadcast(); listenerLists.finishBroadcast();需要成对使用。
每次到了一本新书,就发送各个通知。
[code] //新书到了, 添加一个观察者模式 private void onNewBookArrived(Book book) throws RemoteException { mBookList.add(book); final int count = listenerLists.beginBroadcast(); for (int i = 0; i < count; ++i) { IOnNewBookArrivedListener l = listenerLists.getBroadcastItem(i); if (l != null) { try { l.onNewBookArrived(book); } catch (Exception e) { } } } listenerLists.finishBroadcast(); }
最后我们来看看客户端如何实现的,Activity的oncreate中进行BindService
[code] Intent intent = new Intent(this,BookManagerService.class); bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
获得IBookManager,然后远程调用各个方法,并且注册了一个通知。
[code]private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { bookManager = IBookManager.Stub.asInterface(service); try{ List<Book> list = bookManager.getBookList(); Log.e("xhc",list.toString()); Book book = new Book(3,"好好学习"); bookManager.addBook(book); Book book2 = new Book(4,"天天向上"); bookManager.addBook(book2); list = bookManager.getBookList(); Log.e("xhc",list.toString()); bookManager.registerLintener(iOnNewBookArrivedListener); }catch(Exception e){ e.printStackTrace(); } } };
在onDestory()中注销通知。注销的通知 iOnNewBookArrivedListener,和注册的通知是同一个,因为中间经历了一层binder,所以这个iOnNewBookArrivedListener不是服务端的iOnNewBookArrivedListener,所以服务端使用的 RemoteCallbackList来装。
[code] @Override protected void onDestroy() { super.onDestroy(); try{ if(bookManager != null && bookManager.asBinder().isBinderAlive()){ bookManager.unregisterListener(iOnNewBookArrivedListener); } }catch(Exception e){ } unbindService(serviceConnection); }
刚睡醒。。。。。。。。。。无聊死了。。。。。要是深圳的童鞋们有谁想骑车玩的,拜托叫我一声啊。
源码下载
参考书籍《Android开发艺术探索》
加个好友共同学习(不是公众号):
因为小弟水平有限,如果有写的有问题,希望指出。
相关文章推荐
- 关于Android在线支付Alipay(支付宝)开发的经验分享,androidalipay
- Android 四大组件之Service
- Android -> 怎样避免Handler引起内存泄露
- 006_安装配置 Android Studio(附安装包下载链接)
- Android解决HAXM安装的问题
- 资源整合+《 Android课程视频同步笔记 》
- Android解决“发现了以元素 'd:skin' 开头的无效内容”
- Android: 在真实设备上调试配置
- Android view 事件分发源码解读
- android sqlite3 在cmd中常用命令详解
- Android中viewPager使用指南
- Android StateListDrawable
- android控件edittext-addTextChangedListener监听文本的变化
- 分享实现Android图片选择的两种方式
- Android中进程生命周期的优先级
- Android锁屏后数据改变的解决方案
- Android Studio 修改主题
- Android应用开发-小巫CSDN博客client之获取评论列表
- 如何不屏蔽Android系统的返回按键
- Android5.0+(CoordinatorLayout)