写点什么

跨进程通讯 Binder 的 onTransact 方法一定在 binder 线程池的 binder 线程中执行吗?

用户头像
Android架构
关注
发布于: 8 小时前

clientBinder.doToastString("skt");


return "你好";


}


};


@Override


public IBinder onBind(Intent intent) {


return serverBinder;


}


四.在 Activity 中创建本地 Binder




在 Activity 启动的时候绑定我们的 MyService,同时在 onServiceConnected 回调中传入我们的本地 Binder 到服务端。主要代码如下。


@Override


protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);


setContentView(R.layout.activity_main);


Intent intent = new Intent(this, MyService.class);


bindService(intent,serviceConnection,BIND_AUTO_CREATE);


}


private ServiceConnection serviceConnection = new ServiceConnection() {


@Override


public void onServiceConnected(ComponentName componentName, IBinder iBinder) {


IMyServerAidlInterface serverBinder = IMyServerAidlInterface.Stub.asInterface(iBinder);


try {


String serverStr = serverBinder.getServerStr(clientBinder);


Log.v("MyServiceClient", Thread.currentThread().getName());


Log.v("MyServiceClient",serverStr);


} catch (RemoteException e) {


e.printStackTrace();


}


}


@Override


public void onServiceDisconnected(ComponentName componentName) {


}


}


private IClientAidlInterface.Stub clientBinder = new IClientAidlInterface.Stub() {


@Override


public void doToastString(String str) throws RemoteException {


Log.v("MyServiceClient", Thread.currentThread().getName());


Log.v("MyServiceClient", str);


}


};


同样在上面复制的两个 java 文件中添加一些 log 打印。






下面执行我们的应用程序,log 打印如下:


![在这里插入图片描述](https://img-blog.csdnimg.cn/20190228212901515.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nL


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


mNzZG4ubmV0L2JyYWludHQ=,size_16,color_FFFFFF,t_70)


我们可以清楚的看到两次跨进程通讯请求都得到了正确的结果,但是在 Activity 中的 Binder 的 onTransact 方法和我们的实现的接口方法,确确实实的运行在了主线程,而不是我们的 Binder 线程。服务端的 Binder 回调是在我们的 Binder 线程中的。


那为什么会导致这样的情况呢?


其实这是 Binder 为我们做的小优化。大家想,我们在 onServiceConnected 的方法中,通过 serverBinder 向服务端请求通信(AIDL 的实现默认同步,transact 方法的 flag 参数默认为 0。),因为我们的 onServiceConnected 是运行在主线程的。所以主线程暂时被挂起,等待远程通信的响应。


服务端收到 Client 端的请求后,执行 onTransact 方法然后调用 getServerStr()方法,这两个方法是运行在服务端 Binder 线程中的,没毛病。然后我们在 getServerStr()中通过我们传过来的 Binder 代理,向客户端发起一个远程通信,按理说当客户端收到这个请求后,会在客户端的 Binder 线程中处理。其实不然,我们要知道现在客户端的主线程是被挂起的,它没事干,闲人一个,在等待我们服务端的返回,我们在处理客户端的远程请求时,还要向客户端发起远程请求,所以默认的,服务端的 Binder 线程同样会被阻塞,等待客户端的结果返回,客户端也是得不到回复的,在这样的情况下,客户端的主线程会被用来处理这次远程通信的请求(即向服务端发起远程通信请求的所在线程)。如果我们在客户端的子线程,向服务端发送远程通信请求,那么客户端的子线程会被拿来处理服务端向客户端发起的远程请求,因为你没事干啊,闲人一个。


修改 Activity 中的代码:



在执行我们的应用程序。log 打印如下:



这回客户端的 Binder 的方法回调执行在了子线程,即我们启动远程服务所在的线程。


五.思考




那如果我们的主线程或者说我们请求远程服务的请求不给阻塞会出现什么的结果呢?


那客户端的 Binder 回调当然执行在客户端的 Binder 线程咯,下面我们来验证一下。


修改 copy 的 IMyServerAidlInterface 文件,找到它的 transact 方法,修改最后一个参数值为 FLAG_ONEWAY。


mRemote.transact(Stub.TRANSACTION_getServerStr, _data, _reply, FLAG_ONEWAY);


表示不需要关心服务端的回复。这样我们请求远程服务的线程就不会被阻塞。我们在运行我们的程序。打印如下:



可以看到我们客户端的 Binder 回调在客户端的 Binder 线程中。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
跨进程通讯Binder的onTransact方法一定在binder线程池的binder线程中执行吗?