Android AIDL双向通信
来源:互联网 发布:知左手边那个字怎么读 编辑:程序博客网 时间:2024/06/06 05:53
定义AIDL服务
1.创建.aidl文件
2.SDK生成对应.java文件和Stub内部类
3.通过Service子类将接口暴露给外界
1. 创建.aidl文件
用Java编程语言来构造.aidl文件。每个.aidl文件必须定义一个带方法声明的接口。
AIDL支持以下数据类型:
1.Java基本类型,即int、long、char等;2.String;3.CharSequence;4.List List中的所有元素都必须是AIDL支持的数据类型、其他AIDL接口或你之前声明的Parcelable实现类。5.Map Map中的所有元素都必须是AIDL支持的数据类型、其他AIDL接口或你之前声明的Parcelable实现类。6.其他类型,必须要有import语句,即使它跟.aidl是同一个包下。
AIDL中的方法和变量
• 方法可有零、一或多个参数,可有返回值或void。
• 所有非基本类型的参数都需要标签来表明这个数据的去向:
1.in,表示此变量由客户端设置;2.out,表示此变量由服务端设置;3.inout,表示此变量可由客户端和服务端设置;4.基本类型只能是in。
• 只expose方法,不会expose静态变量。
服务端——服务(Manager.aidl)
// Manager.aidlpackage com.dream.aidl;// Declare any non-default types here with import statementsimport com.dream.aidl.IdCardInfoCallBack;interface Manager { void readCard(String serialPort);//开启读卡 void clearCard();//清除读卡内容 void stopReadCard();//停止读卡}
2. SDK生成对应.java文件和Stub内部类
•当编译APP时,SDK工具会将项目/src/main/aidl目录下的.aidl文件一个个在项目/build/generated/source/aidl目录下生成IBinder接口.java文件。两个文件名一样,只是后缀不同。如Manager.aidl生成Manager.java。
•Stub内部类
▫ .aidl文件编译后生成的.java文件中自动生成的内部类。▫ public static abstract声明。▫ extends android.os.Binder。▫ 实现.aidl文件中定义的接口,且声明其所有方法。
•实现Stub内部类要注意
▫ 对于传过来的调用,无法保证是在主线程中执行的。Service必须要考虑多线程和线程安全。▫ 默认情况下,RPC都是异步的。**避免在主线程中调用AIDL**,不然可能会导致ANR。▫ 不能给调用方回抛异常。
3. 通过Service子类将接口暴露给外界
需要在服务端创建一个Service子类,并在onBind()中返回Stub内部类。
/** * 服务端调用读卡的服务 */public class ReadCardService extends Service { @Override public IBinder onBind(Intent intent) { return mStub; } /** * 实现aidl中的方法 * 不同方法调用不同读卡方法 */ private Manager.Stub mStub = new Manager.Stub() { @Override public void readCard(String serialPort) throws RemoteException { //开启读卡 } @Override public void clearCard() throws RemoteException { //清除读卡 } @Override public void stopReadCard() throws RemoteException { //停止读卡 } };}
AndroidManifest.xml 配置,设置exported为true、自定义action名等。
<service android:name=".ReadCardService" android:enabled="true" android:exported="true" android:process=":remote"> <intent-filter> <action android:name="com.dream.idcard"></action> </intent-filter></service>
调用AIDL服务
• 若客户端组件和服务分开在不同APP,那么客户端所在APP的/src/main/aidl目录下必须要有一份.aidl副本。
• 开启AIDL服务。
Intent intent = new Intent();//android 5.0以后直设置action不能启动相应的服务,需要设置packageName或者Component。intent.setAction("com.dream.idcard");intent.setComponent(new ComponentName("com.dream.readidcard", "com.dream.readidcard.ReadCardService"));//绑定服务bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
• 客户端建立连接后,要将接受到的AIDL服务端iBinder转换为客户端所在APP的/src/main/aidl中的Manager.aidl类型。
private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { try { mStub = Manager.Stub.asInterface(iBinder); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName componentName) { mStub = null; } };
• 可像普通对象一样调用mStub 。注意,AIDL服务默认是运行在主线程中,若里面有耗时操作,应该在子线程中调用AIDL。
AIDL服务回调客户端
首先贴一下项目目录:
1.创建回调使用的aidl:IdCardInfoCallBack.aidl
// IdCardInfoCallBack.aidlpackage com.dream.aidl;/** * Created by mx on 2017-11-8. * 读卡信息回调 */import com.dream.aidl.IdCardInfo;interface IdCardInfoCallBack { void CallBackInfo(in IdCardInfo idCardInfo);}
2.Manager.aidl提供给客户端注册、注销的方法。
// Manager.aidlpackage com.dream.aidl;// Declare any non-default types here with import statementsimport com.dream.aidl.IdCardInfoCallBack;interface Manager { void readCard(String serialPort);//开启读卡 void clearCard();//清除读卡内容 void stopReadCard();//停止读卡 void registerCallBack(in IdCardInfoCallBack cb);//注册回调接口 void unregisterCallBack(in IdCardInfoCallBack cb);//注销回调接口}
3.实现类:ReadCardService
/** * 服务端调用读卡的服务 */public class ReadCardService extends Service { /** * 读卡回调 */ OnReadCardListener onReadCardListener = new OnReadCardListener() { @Override public void onReadCardSuccess(IdCardInfo idCardInfo) { sendResponse(idCardInfo); } }; //我们在服务端通知客户端消息的时候 也害怕 服务端 会异常销毁 导致客户端收不到消息 //好在谷歌早就为我们考虑到这种情况 提供了RemoteCallbackList 来完成对应的功能 //避免我们再重复一遍上述的过程 private RemoteCallbackList<IdCardInfoCallBack> mCallBacks = new RemoteCallbackList<>(); /** * 实现aidl中的方法 * 不同方法调用不同读卡方法 */ private Manager.Stub mStub = new Manager.Stub() { @Override public void readCard(String serialPort) throws RemoteException { //开启读卡 } @Override public void clearCard() throws RemoteException { //清除读卡 } @Override public void stopReadCard() throws RemoteException { //停止读卡 } @Override public void registerCallBack(IdCardInfoCallBack cb) throws RemoteException { if (null != cb) { //注册回调 mCallBacks.register(cb); } } @Override public void unregisterCallBack(IdCardInfoCallBack cb) throws RemoteException { if (null != cb) { //注销回调 mCallBacks.unregister(cb); } } }; @Override public IBinder onBind(Intent intent) { return mStub; } /** * 发送读取的身份证信息 * * @param idCardInfo */ private void sendResponse(IdCardInfo idCardInfo) { // 以广播的方式进行客户端回调 int len = mCallBacks.beginBroadcast(); for (int i = 0; i < len; i++) { try { mCallBacks.getBroadcastItem(i).CallBackInfo(idCardInfo); } catch (RemoteException e) { e.printStackTrace(); } } // 记得要关闭广播 mCallBacks.finishBroadcast(); } @Override public void onDestroy() { super.onDestroy(); mCallBacks.kill();//销毁回调资源 否则要内存泄露 }}
4.客户端调用
//在建立连接时候调用 注册AIDL回调 mStub.registerCallBack(idCardInfoCallBack); /** * AIDL服务端返回数据 */ protected IdCardInfoCallBack idCardInfoCallBack = new IdCardInfoCallBack.Stub() { @Override public void CallBackInfo(IdCardInfo idCardInfo) throws RemoteException { if (null != idCardInfo) { //对UI进行操作 } } };
- Android AIDL双向通信
- Android 跨进程双向通信(Messenger与AIDL)详解
- 使用AIDL双向通信
- AIDL实现跨APP通信(双向通信)
- AIDL 客户端与服务端的双向通信
- AIDL 客户端与服务端的双向通信
- android service与activity双向通信
- Android aidl
- android AIDL
- ANDROID AIDL
- android aidl
- android:aidl
- android AIDL
- android AIDL
- Android AIDL
- android aidl
- android aidl
- android aidl
- Bi-shoe and Phi-shoe
- 改变android状态栏颜色
- leetCode- Maximum Subarray
- float、double计算中精度丢失的处理
- Ubuntukylin16.04.2下anaconda2与anaconda3共存
- Android AIDL双向通信
- 走向程序猿的第一步
- poi导出word
- bzoj 3944 Sum 杜教筛
- css设置小图标
- Linux的帧缓冲(Frame Buffer)之一:原理及控制参数
- HDU 4035 maze 概率期望dp
- Hibernate+EHCache配置二级缓存
- selenium+Chromedriver.exe的位置的设置