AIDL在谷歌官方描述中推荐在 不同应用、多并发任务时使用。
在上一篇的基础上,做一些打印和修改。
主要修改:getName方法为耗时方法。即为 getName方法增加 Thread.sleep(20000);
操作演示
1、修改getName为耗时
2、打印客户端代码
点击TextView,开始进行AIDL连接,在 onServiceConnected 中 使用耗时方法 getName,然后打印。
Button按钮用于触发ANR。为什么要用个Button去触发ANR,因为ANR是说APP无响应,是对某一事件无响应,如果你不去主动触发Button 的 onClick方法,那么这个不弹出ANR异常。
那么我们看点击后的效果。
3、点击AIDL连接,查看客户端打印信息
并没有弹出ANR,因为我点击 “连接AIDL” 按钮后,啥也没做,所以不会触发ANR
我们看客户端打印信息
01-14 17:02:43.553 26563-26563/com.example.yanlong.aidlclient I/客户端: bindAidl() 函数前一行
01-14 17:02:43.553 26563-26563/com.example.yanlong.aidlclient I/客户端: bindAidl() 函数后一行
01-14 17:02:43.553 26563-26563/com.example.yanlong.aidlclient I/客户端: onServiceConnected 中线程名称main
01-14 17:02:43.553 26563-26563/com.example.yanlong.aidlclient I/客户端: onServiceConnected 中获取到 iUserAidlInterface 对象
01-14 17:03:03.553 26563-26563/com.example.yanlong.aidlclient I/客户端: 您好,我的名字叫服务端
可以看到 最后三行。 主线程、获取对象、调用函数。
在主线程中运行,获取对象和调用函数相差20秒。
这时候我们看服务端打印的信息。
01-14 17:02:43.553 24759-24770/com.example.yanlong.aidlservice I/服务端: Binder_1
服务端当前线程名称为 binder_1 ,是个工作线程。这也正好符合了AIDL的 多并发使用。
既然是 binder_1 可以推测可能会有 binder_2 binder_3 等等一系列。
4、我们点一下 Button 会怎么样?
肯定ANR,不贴图了。
如何修改
1、使用子线程去操作耗时请求
两种思路,
①:当 OnClick后,使用工作线程运行其内部的bindAidl();函数。
②:当 准备调用 getName(); 函数时,开启工作线程。
真相如何?答案只有一个,就是 只使用 ② 或 ①+② 使用。
我们看一下打印结果
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i(TAG, "bindAidl() 函数前一行");
new Thread(new Runnable() {
@Override
public void run() {
bindAidl();
}
},"自定义线程").start();
Log.i(TAG, "bindAidl() 函数后一行");
}
});
打印结果如下:
01-14 17:48:48.998 14017-14017/com.example.yanlong.aidlclient I/客户端: bindAidl() 函数前一行
01-14 17:48:48.998 14017-14017/com.example.yanlong.aidlclient I/客户端: bindAidl() 函数后一行
01-14 17:48:48.998 14017-14017/com.example.yanlong.aidlclient I/客户端: onServiceConnected 中线程名称main
01-14 17:48:48.998 14017-14017/com.example.yanlong.aidlclient I/客户端: onServiceConnected 中获取到 iUserAidlInterface 对象
01-14 17:49:08.998 14017-14017/com.example.yanlong.aidlclient I/客户端: 您好,我的名字叫服务端
可以明显看出,即使我们使用子线程去进行AIDL连接,
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected 中线程名称" + Thread.currentThread().getName());
IUserAidlInterface iUserAidlInterface = IUserAidlInterface.Stub.asInterface(service);
Log.i(TAG, "onServiceConnected 中获取到 iUserAidlInterface 对象");
try {
String name1 = iUserAidlInterface.getName();
Log.i(TAG, name1);
} catch (RemoteException e) {
e.printStackTrace();
}
}
onServiceConnected的回调依然是主线程,所以这里建议可以用子线程去开启 AIDL连接,但是一定要在调用远程耗时方法处使用工作线程。
其实从我角度出发来说,只要不涉及到UI更新,我都可能会考虑使用工作线程。当然前提是做好线程同步。