文章大纲

  • 引言
  • 一、远程回调AIDL接口的应用
    • 1、封装基本的父类和一些工具类
    • 2、 创建服务端的AIDL
      • 2.1、定义回调AIDL接口
      • 2.2、定义业务AIDL接口
    • 3、实现服务端对应AIDL的带有回调功能的Service
    • 4、客户端调用服务端带有回调接口AIDL
  • 二、自定义 Parcelable类型AIDL的应用
    • 1、定义一个用于引入自定义Parcelable 类型的AIDL
    • 2、在Java层定义一个实现了Parcelable接口的JavaBean
    • 3、定义使用自定义Parcelable 类型的AIDL的AIDL
    • 4、使用自定义Parcelable 类型的AIDL的Service实现
    • 5、在服务端清单文件注册对应的Service
    • 6、客户端调用服务端自定义Parcelable的AIDL
    • 小结

引言

前一篇Android进阶——AIDL详解之使用远程服务AIDL实现进程间(IPC)简单通信小结(一)简单介绍了AIDL的由来和一些基本的语法知识,结合例子相信对于入门AIDL应该没有什么问题了,前篇讲到AIDL应用主要可以分为三大场景:普通AIDL、带有远程回调接口的AIDL和需要引用自定义Parcelable的AIDL,由于篇幅问题仅仅完成了第一个最简单的场景,这篇就完成剩下的两个场景的应用,系列文章链接如下:

  • Android进阶——AIDL详解之使用远程服务AIDL实现进程间(IPC)简单通信小结(一)
  • Android进阶——AIDL详解之使用远程服务AIDL实现进程间带远程回调接口和自定义Bean的较复杂通信小结(二)
  • Android 进阶——AIDL 详解之AIDL 借助Binder 实现IPC背后的核心思想和原理(三)

一、远程回调AIDL接口的应用

1、封装基本的父类和一些工具类

package com.crazymo.remoteserver.base;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;/*** Auther: Crazy.Mo on 2018/5/7 13:09* Summary:所有远程服务必须继承的父类*/
public abstract class AbstractService extends Service {protected IBinder mBinder;@Nullable@Overridepublic IBinder onBind(Intent intent) {if(mBinder==null){mBinder=initBinder();}return mBinder;//与客户端成功连接上的时候返回给客户端使用的对象}protected abstract IBinder initBinder();
}

在Android5.1之后,仅仅通过setAction无法匿名启动服务了而且还会引发异常,需要做处理。

package com.crazymo.client;import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.util.Log;
import java.util.List;/*** Auther: Crazy.Mo on 2018/5/3 9:35* Summary:这是为了处理高版本下仅仅通过action 匿名启动服务引发的异常*/
public class AIDLUtil {/**** @param pContext* @param pConnection 实现ServiceConnection接口的类* @param action 要启动服务的action* @return*/public static boolean bindAIDLService(Context pContext, ServiceConnection pConnection, String action){boolean isBind=false;if(pContext!=null && action!=null && pConnection!=null) {try {Intent intent = new Intent(getExplicitIntent(pContext, new Intent().setAction(action)));isBind = pContext.bindService(intent, pConnection, Context.BIND_AUTO_CREATE);}catch (Exception e){Log.e("AIDL",e.getMessage());}}return isBind;}private static Intent getExplicitIntent(Context context, Intent implicitIntent) {// Retrieve all services that can match the given intentPackageManager pm = context.getPackageManager();List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);// Make sure only one match was foundif (resolveInfo == null || resolveInfo.size() != 1) {return null;}// Get component info and create ComponentNameResolveInfo serviceInfo = resolveInfo.get(0);String packageName = serviceInfo.serviceInfo.packageName;String className = serviceInfo.serviceInfo.name;ComponentName component = new ComponentName(packageName, className);// Create a new intent. Use the old one for extras and such reuseIntent explicitIntent = new Intent(implicitIntent);// Set the component to be explicitexplicitIntent.setComponent(component);return explicitIntent;}
}

2、 创建服务端的AIDL

和普通Java 回调接口语法不同,需要单独使用一个AIDL文件来定义回调接口。

2.1、定义回调AIDL接口

// IRemoteCallback.aidl
package com.crazymo.remoteserver.callback;interface IRemoteCallback {void afterSpeak(String msg);
}

2.2、定义业务AIDL接口

和不需要回调的接口的AIDL不同,这里必须要定义注册和反注册回调的方法,同时通过import 引入对应的aidl回调

  • 定义注册和反注册回调的方法
  • 引入远程回调对应的aidl描述文件
// IRemoteCallbackApi.aidl
package com.crazymo.remoteserver;
//引入回调接口
import com.crazymo.remoteserver.callback.IRemoteCallback;interface IRemoteCallbackApi {void speak(String msg);void registerListener(IRemoteCallback callBack);//注册void unRegisterListener(IRemoteCallback callBack);//销毁
}

3、实现服务端对应AIDL的带有回调功能的Service

触发回调,需要借助**RemoteCallbackList(一些接口集合用于执行列表中对象的回调函数,主要用于为服务端和客户端通信)**来实现,所谓注册就是将回调接口添加到RemoteCallbackList里,销毁则是从RemoteCallbackList里移除,至于用于在回调的AIDL里做什么不应该由服务提供者来确定,所以无须实现具体业务逻辑。

  • 继承Service,重写onBind方法
  • 继承对应的Stub类,实现AIDL中定义的方法的具体的逻辑
  • onBind方法中返回我们自定义的Stub子类Binder对象
  • 实现AIDL的注册及反注册方法
package com.crazymo.remoteserver.service;import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import com.crazymo.remoteserver.IRemoteCallbackApi;
import com.crazymo.remoteserver.base.AbstractService;
import com.crazymo.remoteserver.callback.IRemoteCallback;/*** Auther: Crazy.Mo on 2018/5/7 17:27* Summary:*/
public class RemoteCallApiService extends AbstractService {private final static String TAG="RemoteService";/*** 和普通AIDL的Service实现不同,添加的代码中比较关键的有两点:注册和反注册远程回调接口* 即将回调对象元素加入或移 除mRemoteCallbackList这个对象中的一个集合,执行回调,将回调方法放在需要执行的地方**/private static RemoteCallbackList<IRemoteCallback> mRemoteCallbackList = new RemoteCallbackList<>();@Overrideprotected IBinder initBinder() {if(mBinder==null){mBinder=new RemoteCallBinder();}return mBinder;}private static final class RemoteCallBinder extends IRemoteCallbackApi.Stub{@Overridepublic void speak(String msg) throws RemoteException {Log.e(TAG,"【服务端】 线程"+Thread.currentThread().getName()+"接到客户端的字符串:"+msg);try {Thread.sleep(100);int count = 0;Log.e(TAG, "mRemoteCallbackList: " +     mRemoteCallbackList+",mRemoteCallbackList.mCallBack:"+mRemoteCallbackList);/***准备开始调用当前注册的回调,这将创建一个回调列表的副本,你可以从使用getBroadcastItem检索条目,而且* 一次只能激活一个广播,所以你必须确保总是从同一个线程调用这个或者是自己做同步。完成后必须调用finishBroadcast。* 返回值:callbacks的大小;如果 mBroadcastCount > 0 说明之前调用过beginBroadcast(),则会抛出异常;**/count = mRemoteCallbackList.beginBroadcast();if (count == 0) {return;}try {for (int i = 0; i < count; i++) {Log.e(TAG,"【服务端】 线程"+Thread.currentThread().getName()+"触发回调方法");mRemoteCallbackList.getBroadcastItem(i).afterSpeak("今天晴,23℃");}} catch (RemoteException e) {e.printStackTrace();} finally {mRemoteCallbackList.finishBroadcast();//必须执行否则有可能会出现状态不合法异常,mBroadcastCount <0 说明之前掉用过finishBroadcast() 则会抛出异常。}} catch (InterruptedException pE) {pE.printStackTrace();}}@Overridepublic void registerListener(IRemoteCallback callBack) throws RemoteException {if (mRemoteCallbackList == null) {return;}mRemoteCallbackList.register(callBack);//注册回调添加到mRemoteCallbackList 里}@Overridepublic void unRegisterListener(IRemoteCallback callBack) throws RemoteException {if(mRemoteCallbackList!=null) {mRemoteCallbackList.unregister(callBack);}}}
}
  • 清单中声明自定义的服务,指定相应的Action和进程
 <service android:name=".service.RemoteCallApiService"android:process=":remotecall"><intent-filter><action android:name="com.crazymo.aidl.callback"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></service>

4、客户端调用服务端带有回调接口AIDL

无论是本地服务还是远程服务,本质上都是Service机制,按照匿名启动Service的步骤来就可以了,所以AIDL的是使用步骤都是:先连接——>在连接回调里初始化远程接口对象——>再通过远程接口对象调用远程方法

  • 引入服务端的AIDL即把服务端AIDL全部文件复制到客户端的aidl目录下
  • 声明远程服务对象实例(类型名为AIDL的名称)
  • 实现并创建远程回调接口对象
  • 声明ServiceConnection对象实例,最好通过继承ServiceConnection实现具体的子类的形式(不要通过匿名内部类的形式创建,因为取消绑定unbindService(ServiceConnection conn)也需要传入ServiceConnection)
  • 通过上下文的bindService(@RequiresPermission Intent service,@NonNull ServiceConnection conn, @BindServiceFlags int flags)匿名启动远程服务
  • ServiceConnection的onServiceConnected完成远程服务对象实例的初始化及对应远程回调接口的注册
  • ServiceConnection的onServiceDisconnected完成远程服务对象实例的销毁及对应远程回调接口的反注册或者重连
  • 通过远程服务对象实例调用远程接口
package com.crazymo.client;import android.app.Activity;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Toast;import com.crazymo.remoteserver.IRemoteApi;
import com.crazymo.remoteserver.IRemoteCallbackApi;
import com.crazymo.remoteserver.IUserMgrApi;
import com.crazymo.remoteserver.bean.User;
import com.crazymo.remoteserver.callback.IRemoteCallback;import java.util.List;//为了节约篇幅,我没有做重连处理,也省掉了一些逻辑,实际应用中为了健壮性应该根据具体情况参照前一篇普通AIDL应用的例子进行完善
public class MainActivity extends Activity {private final static String TAG="RemoteService";private final static String ACTION_CALLBACK="com.crazymo.aidl.callback";private boolean isUnbindRemoteApiConn=false;private RemoteApiConn mRemoteApiConn=new RemoteApiConn();//只要是进程通信都需要实现,因为系统是在这个ServiceConnecttion类的相关方法通过回调返回Ibinder对象的private RemoteCallbackApiConn mCallbackApiConn=new RemoteCallbackApiConn();private IRemoteCallbackApi mRemoteCallbackApi;//实现远程回调接口private IRemoteCallback mIRemoteCallback=new IRemoteCallback.Stub() {@Overridepublic void afterSpeak(String msg) throws RemoteException {Log.e(TAG,"【客户端】线程"+Thread.currentThread().getName()+"远程回调返回的信息:"+msg);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void connCallbackAIDL(View view) {boolean isBind;isBind=AIDLUtil.bindAIDLService(this,mCallbackApiConn,ACTION_CALLBACK);Log.e(TAG,"【客户端】线程"+Thread.currentThread().getName()+"绑定远程带有回调的远程接口(成功true,失败false):  "+isBind);}public void testCallbackAIDL(View view) {if(mRemoteCallbackApi!=null){try {Log.e(TAG,"【客户端】线程"+Thread.currentThread().getName()+"调用带有回调的远程接口,发送:今天天气怎么样");mRemoteCallbackApi.speak("今天天气怎么样");} catch (RemoteException pE) {pE.printStackTrace();}}}private final class  RemoteCallbackApiConn implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mRemoteCallbackApi=IRemoteCallbackApi.Stub.asInterface(service);try {mRemoteCallbackApi.registerListener(mIRemoteCallback);} catch (RemoteException pE) {pE.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {if(mRemoteCallbackApi!=null){try {mRemoteCallbackApi.unRegisterListener(mIRemoteCallback);} catch (RemoteException pE) {pE.printStackTrace();}}}}
}

二、自定义 Parcelable类型AIDL的应用


Android 中进程之间的通信最终都是基于Binder机制的,而AIDL是Binder机制中的一部分,进程之间要想通过AIDL 进行数据传输,发送进程方就必须先把数据进行序列化操作,Android 中序列化没有采用Java 传统的Serializer 方案,而是使用了一种性能更高的独有方案Parcelable(因为传统的Serializer方案的序列化和反序列化操作都是由JVM去完成的,对于开发者来说是黑盒的,在做反序列化时需要去遍历根据字节等判断边界,而Parcelable 则是直接提供序列化和反序列化接口方法,这些接口直接通过JNI 调用本地方法存储到Parcel中,最终存储到Native层),总之AIDL传输非基本类型及集合类型数据时都需要通过Parcelable类型

1、定义一个用于引入自定义Parcelable 类型的AIDL

为了引入实现了Parcelable 的JavaBean到AIDL层,得先建立一个和JavaBean 同名的AIDL文件(一对一的关系),如果需要引入多个JavaBean就得建立多个对应的AIDL文件,这些没有Interface的AIDL文件在编译时就不会生成对应的Java文件,仅仅是起描述Parcelable 类型的作用(不能定义Interface,有多少个Parcelable类型就需要有多少个这种类型的描述AIDL文件)。而且必须要先建立AIDL文件,再去Java 同一包名下建立同名的JavanBean

// User.aidl
package com.crazymo.remoteserver.bean;//为了引入JavaBean到AIDL层,得先建立一个和JavaBean 同名的aidl接口(一对一的关系),如果需要引入多个JavaBean就得建立对应的aidl接口
//这个文件的作用是引入了一个序列化对象 User 供其他的AIDL文件使用
//注意:User.aidl与User.java的包名应当是一样的
parcelable User;

2、在Java层定义一个实现了Parcelable接口的JavaBean

package com.crazymo.remoteserver.bean;import android.os.Parcel;
import android.os.Parcelable;public class User implements Parcelable {private String mName;private int mAge;public User() {}public void setName(String pName) {mName = pName;}public void setAge(int pAge) {mAge = pAge;}protected User(Parcel in) {mName = in.readString();mAge = in.readInt();}/*** 这里new User 对象和下面writeToParcel方法的对象不在同一个进程内,不是同一个对象实例,* 这里是接收进程的User对象实例*/public static final Creator<User> CREATOR = new Creator<User>() {@Overridepublic User createFromParcel(Parcel in) {return new User(in);}@Overridepublic User[] newArray(int size) {return new User[size];}};@Overridepublic int describeContents() {return 0;}/*** 序列化时,写的顺序要和下面读的顺序一致*/@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeString(mName);dest.writeInt(mAge);}public void readFromParcel(Parcel dest) {mName = dest.readString();mAge = dest.readInt();}@Overridepublic String toString() {return "姓名:" + mName + "    " + "年龄:" + mAge;}
}

3、定义使用自定义Parcelable 类型的AIDL的AIDL

使用自定义类型前得先通过import 手动引入且作为参数时必须使用修饰符修饰,一般使用in

// IUserMgrApi.aidl
package com.crazymo.remoteserver;
import com.crazymo.remoteserver.bean.User;//引入
// Declare any non-default types here with import statementsinterface IUserMgrApi {void registUser(inout User user);List<User> getUsers();
}

4、使用自定义Parcelable 类型的AIDL的Service实现

  • 继承Service,重写onBind方法
  • 继承对应的Stub类,实现AIDL中定义的方法的具体的逻辑
  • onBind方法中返回我们自定义的Stub子类Binder对象
package com.crazymo.remoteserver.service;import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;import com.crazymo.remoteserver.IUserMgrApi;
import com.crazymo.remoteserver.base.AbstractService;
import com.crazymo.remoteserver.bean.User;import java.util.ArrayList;
import java.util.List;/*** Auther: Crazy.Mo on 2018/5/7 15:44* Summary:*/
public class RemoteUserApiService extends AbstractService {private final static String TAG="RemoteService";private List<User> mUserList;@Overrideprotected IBinder initBinder() {if(mBinder==null){mBinder=new RemoteUserServiceBinder();}return mBinder;}/*** 继承AIDL文件里的Stub封装IBinder对象,可以理解为AIDL接口的实现*/private final class RemoteUserServiceBinder extends IUserMgrApi.Stub{@Overridepublic void registUser(User user) throws RemoteException {synchronized (this){if(mUserList==null){mUserList=new ArrayList<>();}if(user!=null){mUserList.add(user);Log.e(TAG, "【服务端】 线程"+Thread.currentThread().getName()+"处理客户端的注册请求"+user.toString());}}}@Overridepublic List<User> getUsers() throws RemoteException {synchronized (this){if(mUserList!=null){Log.e(TAG, "【服务端】 线程"+Thread.currentThread().getName()+"处理客户端的获取用户集请求返回List集合");return mUserList;}else{return null;}}}}
}

5、在服务端清单文件注册对应的Service

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.crazymo.remoteserver"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><service android:name=".service.RemoteApiService"android:process=":remote"><intent-filter><action android:name="com.crazymo.aidl.comm"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></service><service android:name=".service.RemoteUserApiService"android:process=":remoteuser"><intent-filter><action android:name="com.crazymo.aidl.user"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></service><service android:name=".service.RemoteCallApiService"android:process=":remotecall"><intent-filter><action android:name="com.crazymo.aidl.callback"/><category android:name="android.intent.category.DEFAULT"/></intent-filter></service></application>
</manifest>

6、客户端调用服务端自定义Parcelable的AIDL

无论是本地服务还是远程服务,本质上都是Service机制,按照匿名启动Service的步骤来就可以了,所以自定义Parcelable的AIDL的是使用步骤都是:先连接——>在连接回调里初始化远程接口对象——>再通过远程接口对象调用远程方法

  • 引入服务端的AIDL即把服务端AIDL全部文件复制到客户端的aidl目录下
  • 引入服务端定义的Parcelable,把服务端定义的实现了Parcelable接口的JavaBean 复制到客户端相同的路径下
  • 声明远程服务对象实例(类型名为AIDL的名称)
  • 声明ServiceConnection对象实例,最好通过继承ServiceConnection实现具体的子类的形式(不要通过匿名内部类的形式创建,因为取消绑定unbindService(ServiceConnection conn)也需要传入ServiceConnection)
  • 通过上下文的bindService(@RequiresPermission Intent service,@NonNull ServiceConnection conn, @BindServiceFlags int flags)匿名启动远程服务
  • ServiceConnection的onServiceConnected完成远程服务对象实例的初始化
  • ServiceConnection的onServiceDisconnected完成远程服务对象实例的销毁或者重连
  • 通过远程服务对象实例调用远程接口
//这里把三种场景使用的完整代码全都贴在一起,做个对比
package com.crazymo.client;import android.app.Activity;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Toast;import com.crazymo.remoteserver.IRemoteApi;
import com.crazymo.remoteserver.IRemoteCallbackApi;
import com.crazymo.remoteserver.IUserMgrApi;
import com.crazymo.remoteserver.bean.User;
import com.crazymo.remoteserver.callback.IRemoteCallback;import java.util.List;public class MainActivity extends Activity {private final static String TAG="RemoteService";private final static String ACTION_COMM="com.crazymo.aidl.comm";private final static String ACTION_PARCE="com.crazymo.aidl.user";private final static String ACTION_CALLBACK="com.crazymo.aidl.callback";private boolean isUnbindRemoteApiConn=false;private RemoteApiConn mRemoteApiConn=new RemoteApiConn();//只要是进程通信都需要实现,因为系统是在这个ServiceConnecttion类的相关方法通过回调返回Ibinder对象的private RemoteUserApiConn mRemoteUserApiConn=new RemoteUserApiConn();private RemoteCallbackApiConn mCallbackApiConn=new RemoteCallbackApiConn();private IRemoteApi mRemoteApi;private IUserMgrApi mUserMgrApi;private IRemoteCallbackApi mRemoteCallbackApi;private IRemoteCallback mIRemoteCallback=new IRemoteCallback.Stub() {@Overridepublic void afterSpeak(String msg) throws RemoteException {Log.e(TAG,"【客户端】线程"+Thread.currentThread().getName()+"远程回调返回的信息:"+msg);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overrideprotected void onDestroy() {super.onDestroy();disconnectRemoteApiComm();}private void disconnectRemoteApiComm() {unbindService(mRemoteApiConn);isUnbindRemoteApiConn=true;}public void connAIDL(View view) {connectAIDL();}private void connectAIDL() {boolean isBind;isBind= AIDLUtil.bindAIDLService(this,mRemoteApiConn,ACTION_COMM);Log.e(TAG,"【客户端】线程"+Thread.currentThread().getName()+"绑定远程接口(成功true,失败false):  "+isBind);if(!isBind){Toast.makeText(this,"连接远程服务发生异常",Toast.LENGTH_SHORT).show();}}public void useAIDL(View view) {if(mRemoteApi==null){connectAIDL();}try {if(mRemoteApi!=null) {//这里有必要Log.e(TAG, "【客户端】线程"+Thread.currentThread().getName()+"通过AIDL调用远程接口,客户端:小鸡炖蘑菇");String result=mRemoteApi.getRemoteStr();Log.e(TAG, "【客户端】线程"+Thread.currentThread().getName()+"服务端响应请求返回:" +result );}} catch (RemoteException pE) {pE.printStackTrace();}}public void connUserAIDL(View view) {boolean isBind;isBind= AIDLUtil.bindAIDLService(this,mRemoteUserApiConn,ACTION_PARCE);Log.e(TAG,"【客户端】线程"+Thread.currentThread().getName()+"绑定远程用户管理接口(成功true,失败false):  "+isBind);if(!isBind){Toast.makeText(this,"连接远程用户管理服务发生异常",Toast.LENGTH_SHORT).show();}}public void testUserAIDL(View view) {try {User user=new User();user.setName("CrazyMo");user.setAge(1);Log.e(TAG, "【客户端】线程"+Thread.currentThread().getName()+"通过AIDL调用远程用户管理接口注册用户:"+user.toString());mUserMgrApi.registUser(user);Log.e(TAG, "【客户端】线程"+Thread.currentThread().getName()+"通过AIDL调用远程用户管理接口查询用户集");List<User> list=mUserMgrApi.getUsers();if(list!=null){for (User tmp :list){Log.e(TAG, "【客户端】线程"+Thread.currentThread().getName()+"远程用户管理接口返回的用户数据:"+tmp.toString());}}} catch (RemoteException pE) {pE.printStackTrace();}}public void connCallbackAIDL(View view) {boolean isBind;isBind=AIDLUtil.bindAIDLService(this,mCallbackApiConn,ACTION_CALLBACK);Log.e(TAG,"【客户端】线程"+Thread.currentThread().getName()+"绑定远程带有回调的远程接口(成功true,失败false):  "+isBind);}public void testCallbackAIDL(View view) {if(mRemoteCallbackApi!=null){try {Log.e(TAG,"【客户端】线程"+Thread.currentThread().getName()+"调用带有回调的远程接口,发送:今天天气怎么样");mRemoteCallbackApi.speak("今天天气怎么样");} catch (RemoteException pE) {pE.printStackTrace();}}}private final class RemoteApiConn implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mRemoteApi=IRemoteApi.Stub.asInterface(service);//初始化远端服务对象实例}@Overridepublic void onServiceDisconnected(ComponentName name) {if(isUnbindRemoteApiConn){mRemoteApi=null;//主动断开直接置为null}else{while(mRemoteApi==null) {connectAIDL();//做重连}}}}private final class RemoteUserApiConn implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mUserMgrApi= IUserMgrApi.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {mUserMgrApi=null;}}private final class  RemoteCallbackApiConn implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mRemoteCallbackApi=IRemoteCallbackApi.Stub.asInterface(service);try {mRemoteCallbackApi.registerListener(mIRemoteCallback);} catch (RemoteException pE) {pE.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName name) {if(mRemoteCallbackApi!=null){try {mRemoteCallbackApi.unRegisterListener(mIRemoteCallback);} catch (RemoteException pE) {pE.printStackTrace();}}}}
}

小结

AIDL的使用到此基本结束了,要记住AIDL本质上也是一种特殊的Service,所以使用它的基本流程和使用本地服务基本一致先连接——>在连接回调里初始化远程接口对象——>再通过远程接口对象调用远程方法。源码传送门

Android进阶——AIDL详解之使用远程服务AIDL实现进程间带远程回调接口和自定义Bean的较复杂通信小结(二)相关推荐

  1. Android进阶——Preference详解之Preference系的基本应用(三)

    引言 前面一篇文章Android进阶--Preference详解之Preference系的基本应用和管理(二)介绍了二级Preference的使用和特点,接下来进入系统给我提供的底级Preferenc ...

  2. android preference属性,Android进阶——Preference详解之Preference系的基本应用和管理(二)...

    并非我们第一次打开相应界面之后就会自动创建对应的SharedPreferences文件,而是在我们改变了原有状态时候喎�"/kf/ware/vc/" target="_b ...

  3. Android进阶——Preference详解之初识Preference及Preference系(一)

    引言 很久没来得及更新博客了,时间总是不够,以前的知识还没来得及总结完毕,新的知识又源源不断地接触到,工作也很忙,但还是没有忘记自己最低点目标每个月至少四篇.好了,废话就到这里啦,开始进入正文,这篇文 ...

  4. Android四大组件Service之AIDL详解

    Android四大组件Service之AIDL详解 前言 简介 基础知识 AIDL 服务端 定义AIDL文件规则 创建 .aidl 文件 清单注册 通过 IPC 传递对象 调用 IPC 方法 Andr ...

  5. Android自定义View进阶-MotionEvent详解

    欢迎Follow我的GitHub, 关注我的CSDN. 其余参考Android目录 我们微信公众号:杨守乐 推荐文章: 如果你喜欢上了一个程序员小伙,献给所有的程序员女友 学习资料(干货汇集)不断更新 ...

  6. Android自定义控件进阶13-MotionEvent详解

    Android MotionEvent 详解,之前用了两篇文章 事件分发机制原理 和 事件分发机制详解 来讲解事件分发,而作为事件分发主角之一的 MotionEvent 并没有过多的说明,本文就带大家 ...

  7. [Android]多进程知识点详解

    作者:Android开发_Hua 链接:https://www.jianshu.com/p/e0f833151f66 多进程知识点汇总: 一:了解多进程 二:项目中多进程的实现 三:多进程的优缺点与使 ...

  8. Android Framework系统服务详解

    Android Framework系统服务详解 操作环境 系统:Linux (Ubuntu 12.04) 平台:高通 Android版本:5.1 PS: 符号...为省略N条代码 一.大致原理分析 A ...

  9. Android Studio 插件开发详解四:填坑

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78265540 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

最新文章

  1. 掌握好这些不变的底层知识,任他东西南北风!
  2. mate7刷android 6.0,华为Mate7 6.0系统刷recovery_Mate7 6.0专用第三方recovery
  3. 联想扬天T4900v开启VT-x方法
  4. Start application automatically during controller boot-up
  5. 数据结构课上笔记14
  6. qt中树形控件QTreeWidget的项点击后获取该项的文本
  7. 清空邮件队列中的邮件
  8. Lucene学习之四:Lucene的索引文件格式(3)
  9. Nginx解决前端调用后端接口跨域问题
  10. SparkSQL Catalog的作用和访问Hive元数据信息
  11. python爬虫教程-Python爬虫五大零基础入门教程
  12. inlfuxdb版本_InfluxDB安装及配置
  13. 手机组态软件_安卓平板组态软件​_移动端组态软件介绍
  14. 进制转换(简单的能看懂就够了)
  15. php cbd架构,ThinkPHP教程--15--CBD模式
  16. c语言大小写字母互换1005,1005 Jugs,1005jugs
  17. LoadRunner测试结果分析重要环节:合并图
  18. 中国造车要把百年车企按在地上打?你别说,我看有戏。
  19. 省市县结合身份证号6位码的三级联动
  20. Android警告信息:Use Autofill

热门文章

  1. Welcome To Jekyll
  2. C语言内存讲解-详说内存分布和heap空间
  3. 奇怪的知识又增加了8——Wi-Fi
  4. 【全站首发】最详细的jetbrains space使用方法
  5. python3爬虫——多线程爬取斗图网表情包
  6. 虚拟机下linux安装nginx
  7. 美团收购摩拜解开资本死结,是王兴进军新零售的前奏?
  8. matlab 灰度图与索引图
  9. web前端开发技术现状与发展_Web前端的发展前景、最新技术、学习路线?
  10. 1091 Acute Stroke (PAT甲级)