Android IPC之AIDL使用解析
来源:互联网 发布:seo推广渠道 编辑:程序博客网 时间:2024/05/17 07:13
在上一篇中介绍了通过Messenger实现IPC的具体方式,但是Messenger在实现IPC存在着一些局限性:
- Messenger只支持单线程通信,无法处理并发请求。
- Messenger只能用于进程间消息传递,在客户端无法调用服务端的方法。
正是由于Messenger的这两点局限性,我们需要使用AIDL来实现IPC。这里特别指出Messenger底层也是通过AIDL实现的。
AIDL简介
AIDL,Android接口定义语言,用于IPC。
- 只有允许不同应用的客户端用IPC方式访问服务,并且想要在服务中处理多线程时,才有必要使用 AIDL。
- 如果您不需要执行跨越不同应用的并发IPC,就应该通过实现一个 Binder 创建接口;
- 如果您想执行 IPC,但根本不需要处理多线程,则使用Messenger 类来实现接口。
AIDL实现IPC流程
AIDL实现流程
- 在服务端创建一个aidl接口,并定义方法。
- 在服务端创建一个Service,并创建AIDL对应的binder对象,将该对象作为service的onBind方法的返回值。
- 在客户端通过绑定服务获取binder对象,通过binder对象生成指定的接口对象。
这里需要注意:
- 在客户端绑定服务前,需要将服务端的AIDL相关的文件都copy到客户端中,并保持文件目录一致。因为在客户端需要反序列化服务端中和AIDL相关的类,如果路径不一致,则无法反序列化成功。所以这里建议大家把与AIDL相关的类文件都放在同一个包下。
- 在aidl接口中仅支持方法,而不能定义静态字段。
- 当我们使用自定义Parcelable对象时,那么必须创建一个和该对象的同名aidl文件。并且需要在aidl文件中通过import导入,即使自定义对象和aidl文件在同一个包下也需要显式导入。
AIDL支持的数据类型
- Java 编程语言中的所有原语类型(如int、long、char、boolean 等等)
- String和CharSequence
- List,List中所有保存的类型必须是AIDL支持的类型,其中在服务端支持使用List作为通用类,但是在客户端实际接收的具体类始终是 ArrayList,但生成的方法使用的是 List 接口。
- Map,Map中所有保存的类型必须是AIDL支持的类型,其中在服务端不支持Map作为通用类,但是在客户端实际接收的具体类始终是 HashMap,但生成的方法使用的是 Map 接口。
在aidl接口中,除了基本类型的参数,其他自定义类型的参数都要指定数据走向,有in、out 或 inout这三种类型,默认是in。
AIDL实例演示
服务端程序
创建一个aidl文件,名称为IBookManager并实现两个方法,代码如下:
package com.zhangke.aidlservicedemo;import com.zhangke.aidlservicedemo.Book;interface IBookManager { List<Book> getBookList(); void addBook(in Book book);}
这里需要注意因为我们使用了自定义类型Book,所以需要创建一个名称同Book相同的aidl文件,只需要通过parcelable定义一下即可,代码如下:
package com.zhangke.aidlservicedemo;parcelable Book;
然后,创建一个Service用于将Aidl对应的binder对象返回到客户端,代码如下:
package com.zhangke.aidlservicedemo;public class BookManagerService extends Service { public static final String TAG = "zhangke"; //支持并发读写的List private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>(); @Override public IBinder onBind(Intent intent) { return mBinder; } private Binder mBinder = new IBookManager.Stub() { @Override public List<Book> getBookList() throws RemoteException { Log.e(TAG, "query book list..."); return mBookList; } @Override public void addBook(Book book) throws RemoteException { Log.e(TAG, "add book ..."); mBookList.add(book); } }; @Override public void onCreate() { super.onCreate(); Log.e(TAG, "service onCreate"); }}
客户端程序
在客户端我们只需要通过绑定服务的方式获取到指定的aidl接口就能调用服务端的方法,代码如下:
package com.zhangke.aidlclientdemo;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.View;import com.zhangke.aidlservicedemo.Book;import com.zhangke.aidlservicedemo.IBookManager;import com.zhangke.aidlservicedemo.IOnBookUpdateListener;import java.util.List;public class MainActivity extends AppCompatActivity { public static final String TAG = "zhangke"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); intent.setComponent(new ComponentName("com.zhangke.aidlservicedemo", "com.zhangke.aidlservicedemo.BookManagerService")); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } IBookManager mIBookManager = null; ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mIBookManager = IBookManager.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, "onServiceDisconnected"); } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(mConnection); } int bookId = 1; public void add(View view) throws RemoteException { Log.e(TAG, Thread.currentThread().toString()); mIBookManager.addBook(new Book(++bookId, "android#" + bookId)); } public void query(View view) throws RemoteException { List<Book> bookList = mIBookManager.getBookList(); for (Book book : bookList) { Log.e(TAG, book.toString()); } }}
效果如下:
我们通过点击添加Book和查询Book就能调用的方法,通过日志我们可以看到服务端方法调用成功。
02-13 03:22:30.079 6511-6522/com.zhangke.aidlservicedemo E/zhangke: add book ...02-13 03:22:31.280 6511-6523/com.zhangke.aidlservicedemo E/zhangke: query book list...02-13 03:22:31.280 6870-6870/com.zhangke.aidlclientdemo E/zhangke: [bookId: 2, bookName:book#2]02-13 03:22:31.280 6870-6870/com.zhangke.aidlclientdemo E/zhangke: [bookId: 3, bookName:book#3]02-13 03:22:31.280 6870-6870/com.zhangke.aidlclientdemo E/zhangke: [bookId: 4, bookName:book#4]
这样,整个通过aidl实现IPC的基本流程就结束了。
AIDL常见问题解析
- 客户端在远程调用服务端方法时,被调用的方法是运行在服务端的binder线程池中的,此时客户端会处于挂起状态,如果服务端方法为耗时方法,如果客户端是在UI线程中调用该远程方法,可能会导致ANR。
Binder异常终止
在通过binder调用远程服务的方法时,有可能会出现服务端程序异常终止的情况,这样客户端的方法就不能正常被调用,这个时候我们需要通过重新连接服务来保证程序的健壮性。
重新连接服务有两种方式:
- 通过给binder设置DeathRecipient,在binder死亡时,DeathRecipient的binderDied方法会被调用;
- 通过ServiceConnection的onServiceDisconnected方法监听服务的异常终端,然后在该方法中设置重连。
代码如下:
ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mIBookManager = IBookManager.Stub.asInterface(service); try { //1、通过deathRecipient方式监听异常中断 service.linkToDeath(deathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, "onServiceDisconnected"); mIBookManager = null; //2、设置重连 linkServer(); }};final IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { Log.e(TAG, "binder death"); //1、设置重连 linkServer(); }};public void linkServer(){ Intent intent = new Intent(); intent.setComponent(new ComponentName("com.zhangke.aidlservicedemo", "com.zhangke.aidlservicedemo.BookManagerService")); bindService(intent, mConnection, Context.BIND_AUTO_CREATE);}
项目代码
0 0
- Android IPC之AIDL使用解析
- Android IPC机制之AIDL的使用
- Android IPC之AIDL的使用
- Android IPC之AIDL
- Android IPC 之AIDL
- Android IPC之AIDL
- Android IPC 之 AIDL
- Android IPC之AIDL
- Android之AIDL使用解析
- Android IPC之AIDL浅谈
- android IPC机制之 AIDL
- Android之使用AIDL进行IPC(一)
- 【Android】Android开发之IPC进程间通信-AIDL介绍及实例解析
- android进程间通信(IPC)之AIDL
- 【Android机制】IPC机制之AIDL
- Android IPC 之 AIDL(一)
- Android IPC 之 AIDL (二)
- Android进程间通信(IPC)之AIDL
- QT .pro文件 LIBS用法详解
- Android内存泄漏总结
- 背包问题的动态规划形式解
- 快速幂——模板
- 简单的利用系统控制器的视屏播放器
- Android IPC之AIDL使用解析
- 关于mysql中的information_schema.tables和information_schema.columns详解
- object-c和swift 混编
- Java变量类型
- 文章标题
- awk处理文件
- Tomcat 8(四)server.xml的Cluster标签详解
- 论文提要“Fast Feature Pyramids for Object Detection”
- c内存分配