Handler进程间通信
来源:互联网 发布:搜狐网络大厦it 编辑:程序博客网 时间:2024/06/07 05:16
Handler在线程间通信很常用,进程间通信却用的很少,书中有介绍自己试用了一下,觉得不是很好用,而且底层也是AIDL,也是Binder,其实没差别,还很绕。
客户端为一个Acitvity 代码如下
package com.xue.qin.demo.message;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;import android.view.View;import android.widget.Button;/** * Created by xue.qin on 2017/6/12. */public class ClientActivity extends Activity implements View.OnClickListener { private static final String TAG = "ClientActivity"; Button mButton; private Messenger mService; private Messenger mMessenger = new Messenger(new Handler() { @Override public void handleMessage(Message msgFromServer) { Log.i(TAG, "Client Get Message :" + msgFromServer); super.handleMessage(msgFromServer); } }); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mai_activity_layout); mButton = (Button) findViewById(R.id.sendMessage); mButton.setOnClickListener(this); Intent startService = new Intent("remoteService"); startService.setPackage(getPackageName()); bindService(startService, mConn, Context.BIND_AUTO_CREATE); } private ServiceConnection mConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = new Messenger(service); Log.i(TAG, "onServiceConnected()"); } @Override public void onServiceDisconnected(ComponentName name) { mService = null; Log.i(TAG, "onServiceDisconnected()"); } }; @Override protected void onDestroy() { unbindService(mConn); super.onDestroy(); } @Override public void onClick(View v) { try { if (mService != null) { Message msg = Message.obtain(); //从消息池中取出最靠前的消息,如果没有消息就新建一个,然后重新赋值 msg.what = 1234; msg.arg1 = 1; msg.arg2 = 2; msg.replyTo = mMessenger; mService.send(msg); } } catch (RemoteException e) { e.printStackTrace(); } }}
在声明一个服务端的Service,是在不同进程Xml写成如下
<service android:name=".ServerService" android:process=".remote"> <intent-filter> <action android:name="remoteService"></action> </intent-filter> </service>
Service代码如下:
package com.xue.qin.demo.message;import android.app.Service;import android.content.Intent;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.support.annotation.Nullable;import android.util.Log;/** * Created by xue.qin on 2017/6/12. */public class ServerService extends Service { private static final String TAG = "ServerService"; Messenger mMessenger = new Messenger(new Handler() { @Override public void handleMessage(Message fromClient) { Log.i(TAG, "msg = " + fromClient); try { Message toClient = Message.obtain(); toClient.what = 1234; toClient.arg1 = fromClient.arg1 + 1; toClient.arg2 = fromClient.arg2 + 1; fromClient.replyTo.send(toClient); } catch (RemoteException e) { e.printStackTrace(); } super.handleMessage(fromClient); } }); @Nullable @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); }}
因为是AIDL,本质应该是相同的,那么走一遍AIDL的流程,就明白了。
1)绑定Service。
2)返回onBind() 返回 Binder,这里和AIDL不一样是Messenger获得的BInder,去看一下源码是怎么回事。
Messenger.java
public Messenger(Handler target) { mTarget = target.getIMessenger(); }
Messenger的声明实例使用了这个构造函数, 去看一下Handler里个getIMessenger()。
Handler.java
final IMessenger getIMessenger() { synchronized (mQueue) { if (mMessenger != null) { return mMessenger; } mMessenger = new MessengerImpl(); return mMessenger; } }
这里new的这个内部类是这样的。
private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }
这个就是是AIDL的生成的BInder类,native方法,没去看了。可以肯定的是这里的参数msg就是到底层转了一圈回来的客户端msg。
那它一定有个aidl文件,叫IMessenger.aidl,这个Handler类都没有引用包,那么应该就在同一个包里面了,果然找到了,代码如下。
文件位置:alps/frameworks/base/core/java/android/os
/* //device/java/android/android/app/IActivityPendingResult.aidl**** Copyright 2007, The Android Open Source Project**** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at **** http://www.apache.org/licenses/LICENSE-2.0 **** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License.*/package android.os;import android.os.Message;/** @hide */oneway interface IMessenger { void send(in Message msg);}
隐藏的接口,其中AIDL的方法还提供了oneway这个关键字,可以用关键字oneway来标明远程调用的行为属性,使用了该关键字,那么远程调用将仅仅是调用所需的数据传输过来并立即返回,而不会等待结果的返回,也即是说不会阻塞远程线程的运行。
这点和没有标记oneway的挂起等待返回,是不一样的。
就一个方法 send(),再往后就是BInder转发了,好的到这知道服务端这边返回的了。
3)客户端接收Binder。
@Override public void onServiceConnected(ComponentName name, IBinder service) { mService = new Messenger(service); Log.i(TAG, "onServiceConnected()"); }
绑定成功接收返回的binder,看一下这个构造函数。
public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target); }
和AIDL一模一样,将这个Ibinder接收过来只有装饰了起来。猜测,客户端发送时就是要用这个target装饰成的Proxy的send来转发到服务端了,看一下是不是这样。
3)客户端调用本地方法。
try { if (mService != null) { Message msg = Message.obtain(); //从消息池中取出最靠前的消息,如果没有消息就新建一个,然后重新赋值 msg.what = 1234; msg.arg1 = 1; msg.arg2 = 2; msg.replyTo = mMessenger; mService.send(msg); } } catch (RemoteException e) { e.printStackTrace(); }
这里mService.send(msg),看一眼源码
public void send(Message message) throws RemoteException { mTarget.send(message); }果然是这个代理发送的。
4)服务端 由Binder来映射调用。还记得之前服务端的Messenger里的Handler里的Stub吗,再粘一遍,这里就调用自己发送sendMessenge了。
private final class MessengerImpl extends IMessenger.Stub { public void send(Message msg) { msg.sendingUid = Binder.getCallingUid(); Handler.this.sendMessage(msg); } }
5)服务端处理返回结果。
这里虽然不会挂起,但是也还是可以返回结果的,什么时候接收到就不一定了,Handler本就是这样。
服务端向客户端发送的代码
try { Message toClient = Message.obtain(); toClient.what = 1234; toClient.arg1 = fromClient.arg1 + 1; toClient.arg2 = fromClient.arg2 + 1; fromClient.replyTo.send(toClient); } catch (RemoteException e) { e.printStackTrace(); }
replyTo是客户端发过来的,这里的调用时调用的Messenger里的Handler里的sendMessage,客户端肯定是可以收到的,当然也是在底层转了一圈,但是在应用这边,可以理解为就是ClientActivity 中的 Handler。
6)客户端接收,本地Handler本地接收。没问题。
这就完成了一次通信,这种通信觉得好绕而且不同步,没用过,看到书上写的,就看了一下。
验证一下,看看从Service返回的值。是不是加了1
01-01 20:36:53.107 12387-12387/com.xue.qin.demo.message I/ClientActivity: Client Get Message :{ when=-1ms what=1234 arg1=2 arg2=3 target=com.xue.qin.demo.message.ClientActivity$1 }
OK
- Handler进程间通信
- 进程间通信--Handler的详解
- 使用handler实现进程间通信
- Handler进程之间通信
- 关于android进程间通信(handler、messenger、AIDL)
- Android组件与进程间的通信-Handler
- 主进程与子进程的通信(handler)
- 进程&进程间通信
- Android线程间通信--Handler
- 线程间通信之Handler
- 线程间通信via Handler
- Android 线程间通信------handler
- 信号通信(进程间通信)
- 进程间通信-管道通信
- 进程间通信--管道通信
- handler进程间通讯机制
- [进程通信] 进程间通信 之 管道
- Handler通信
- android 智能代码提示 && 代码风格
- 删除TFS版本文件以及项目中的残留节点
- JSP
- mysql
- python函数学习一(跳出函数)
- Handler进程间通信
- PHP Curl工具类
- VueJs2.0建议学习路线
- 设计模式大杂烩(24种设计模式的总结以及学习设计模式的几点建议)
- Pythone3.X的dict字典
- ngnix转发功能
- 程序猿_给你一打肤白貌美的鼓励师你要吗?
- Mac虚拟机与双系统哪个才是你的菜
- 爱测未来安全-前端性能测试平台及应用