Android之进程间通信(IPC)-Messenger
来源:互联网 发布:java中flag的用法 编辑:程序博客网 时间:2024/05/16 07:50
Android之进程间通信(IPC)-Messenger
文章连接:http://blog.csdn.net/qq_16628781/article/details/70087623
知识点:
- 进程间通信的几种方式;
- Android中利用messenger信使进行通信;
- 新名词记录{IPC机制;ContentProvider;Socket;AIDL;Messenger}
概述
众说周知,如果需要跨进程通讯,有几个方法来实现:IPC机制(Android利用Binder),Bundle/Intent传递数据,文件共享,Messenger,ContentProvider,Socket和AIDL。
其中Bundle/Intent我们用的最多,基本上都是在页面之间传递数据。但是只能够传递基本的数据类型,而且都是要实现Serializable或Parcellable接口的数据结构。利用bundle和intent传递是对数据进行序列化和反序列化的,实现了Serializable或Parcellable接口的类,都能够进行序列化和反序列化操作。查看Java序列化和反序列化
文件共享,相同进程或者不同进程间对同一个文件进行读写操作,从而可以达到进程通信或者是进程数据共享。
AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理。
其它的就不讲了,大伙可以自个去搜一下。
Messenger进程间通信
这里我就只讲Messenger信使进行进程间通信。Messenger是基于AIDL实现的,服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler来创建Messenger,在onBind时返回Messenger的binder。双方用Messenger来发送数据,用Handler来处理数据。Messenger处理数据依靠Handler,所以是串行的,也就是说,Handler接到多个message时,就要排队依次处理。
下面是实战过程。
首先是远程进程。这里的远程进程,我们利用Androidmanifest文件里面的process属性来设置。如下所示:
<service android:name=".db.share.MessengerService" android:enabled="true" android:exported="true" android:process=":messenger" android:permission="com.yaojt" />
name:就是继承自service的远程服务类。就是下面的MessengerService.java类;
android:process = 告诉系统我要运行在messenger的进程中。
android:permission=”com.yaojt” -定义此服务的权限,否则所有的进程都能够访问此服务,这是不安全的。
package com.yaojt.db.share;/** * desc:服务端的service * <p> * author:kuyu.yaojt (tanksu) * <p> * email:yaojt@kuyumall.com * <p> * blog:http://blog.csdn.net/qq_16628781 * <p> * date:17/4/11 */public class MessengerService extends Service { public MessengerService() { } @Override public void onCreate() { super.onCreate(); long curId = Thread.currentThread().getId(); CommonLog.logInfo("---->>", "MessengerService的线程id(onCreate)= " + curId + "\n 线程名字:" + Thread.currentThread().getName()); } /** * 创建一个Messenger,并与一个handler关联 */ private Messenger messenger = new Messenger(new ServerHandler()); @Nullable @Override public IBinder onBind(Intent intent) { return messenger.getBinder(); } /** * 接收和处理客户端发来的信息 */ public static class ServerHandler extends Handler { public final static int MSG_FROM_CLIENT = 0; public final static int MSG_FROM_SERVER = 1; @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == MSG_FROM_CLIENT) { Bundle bundleGet = msg.getData(); String strFromClient = bundleGet.getString("clientKey"); CommonLog.logInfo("----->server.handler", strFromClient); Messenger clientMessenger = msg.replyTo; Message replyMsg = Message.obtain(null, MSG_FROM_SERVER); Bundle bundle = new Bundle(); bundle.putString("serverKey", "note: this message come from server!"); replyMsg.setData(bundle); try { clientMessenger.send(replyMsg); } catch (RemoteException e) { e.printStackTrace(); } } } }}
在远端的进程中,首先打印出当前线程的id和name。因为选择bindservice()方法来启动服务,所以只重写onBind(Intent intent)方法。
我们先注意到这个语句:
private Messenger messenger = new Messenger(new ServerHandler());
Messenger是直接实现了Parcelable接口,所以他得以序列化和反序列化。因为service通过binder进行通信,所以信使类Messenger在onbind的时候,返回IBinder类或者其子类。
在ServerHandler类里面进行处理另一个进程传过来的信息。可以利用msg.getData()方法得到bundle,依次取出数据。同样的,在另一进程中,还将信使利用msg.replyTo传递过来了。我们可以获取到这个信使,发送消息出去,最后与传递过来的信使关联的handler就可以接收到消息并进行处理了。信使调用send()方法,其实和handler调用sendMessage()方法是一样的。
这里快速复习下:启动一个service,有两种方法:startservice()和bindservice()。startservice()首先会调用service里面的oncreate()方法,然后调用onStart()方法,在启动它的组件销毁之后,service会继续运行,和组件不是同生共死。bindservice()方法,如果service已经启动,那么就不会再调用oncreate()方法了,会直接调用service里面的onBind()方法。
如何结束service:bindservice()的可以不用管理,启动它的组件被销毁了,那么service也会随之销毁。如果是startservice()启动的service,在完成service的任务之后,一般是耗时操作,我们可以调用stopSelf()方法停止该service了。
然后我们就在activity里面启动该service,注意因为我们设置了改service是运行在另一个进程中的。
package com.yaojt.db.share;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Build;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 com.yaojt.sdk.java.utils.CommonLog;import com.yaojt.ui.BaseActivity;/** * desc: * <p> * author:kuyu.yaojt (tanksu) * <p> * email:yaojt@kuyumall.com * <p> * blog:http://blog.csdn.net/qq_16628781 * <p> * date:17/4/11 */public class ServiceClientActivity extends BaseActivity { private final String TAG = this.getClass().getSimpleName(); /** * 给服务端发消息的Messenger */ private Messenger mMessenger; /** * 接收服务端消息的Messenger * */ private Messenger mClientMessager = new Messenger(new ClientHandler()); private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { CommonLog.logInfo("连接服务成功!"); onConnected(name, service); } @Override public void onServiceDisconnected(ComponentName name) { CommonLog.logInfo("连接服务失败!"); } }; private void onConnected(ComponentName name, IBinder service) { Messenger mMessenger = new Messenger(service); //参数2是what的静态方法 Message msg = Message.obtain(null, MessengerService.ServerHandler.MSG_FROM_CLIENT); //在客户端带入数据 Bundle bundle = new Bundle(); bundle.putString("clientKey", "note: this message come from client!"); msg.setData(bundle); msg.replyTo = mClientMessager; try { mMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { super.onCreate(savedInstanceState); } long curId = Thread.currentThread().getId(); CommonLog.logInfo("---->>", "ServiceClientActivity的线程id= " + curId + "\n 线程名字:" + Thread.currentThread().getName()); initData(); } public void initData() { Intent intent = new Intent(this, MessengerService.class); /** * 参数1:intent * 参数2:service的通断的监听 * 参数3:标志。BIND_AUTO_CREATE:自动创建service; * */ bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } /** * 接收和处理服务端发来的信息的handler */ public static class ClientHandler extends Handler { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == MessengerService.ServerHandler.MSG_FROM_SERVER) { //来自服务的数据 Bundle bundle = msg.getData(); String strFromServer = bundle.getString("serverKey"); CommonLog.logInfo("---->client.handler", strFromServer); } } } @Override protected void onDestroy() { super.onDestroy(); //需要解绑服务,否则内存泄漏 unbindService(mServiceConnection); }}
这里,和远程进程相类似的,只是我们这里调用了bindservice()方法启动服务,然后我们这里给启动的结果设置一个成功和失败的监听。我们只要在成功的回调里面给远程进程发送数据。
我们看到这里
private Messenger mClientMessager = new Messenger(new ClientHandler());
这里是定义一个此进程用来处理远端进程返回来的消息的信使,对应的代码是msg.replyTo = mClientMessager;远端进程正获取此进程的信使实体类,然后进行数据发送的。通过mClientMessager发送的消息,就和调用sendMessage()方法发送消息一样。
注意:是重要记得解绑服务,unbindService(),否则IDE会报一个内存泄漏的异常
关于bindService()方法参数3的说明:
BIND_DEBUG_UNBIND:仅在debug时候使用,因为设置此标志,就不会调用unbindService()方法释放服务,
它的生命周期就和APP一样长了,极有可能造成内存泄漏;
BIND_ABOVE_CLIENT:设置服务的重要性比app要大;这是一个保活的策略之一哈;
BIND_WAIVE_PRIORITY:设置此服务像APP一样,运行在后台;
BIND_IMPORTANT:提升服务的优先级别为前台进程;
BIND_ADJUST_WITH_ACTIVITY:提升服务的优先级和activity一样高;
BIND_ALLOW_WHITELIST_MANAGEMENT:提升服务优先级为白名单,最后你懂滴;
还有好多个,有兴趣的可以去看源码。
最后记得在Androidmanifest文件注册上面的activity
<activity android:permission="com.yaojt" android:name=".db.share.ServiceClientActivity" android:screenOrientation="portrait" />
最后来看一下运行的截图;
activity进程
远端进程:
总结
我们知道了跨进程间通信有哪几个方式,这里介绍了利用信使messenger来进行通信。说白了,这里是通过传递信使messenger,利用获取到的messenger进行发送message,那么与获取到的messenger相关连的handler就可以接收到消息了。
以上就是所有内容,如有任何问题,请及时与我联系,谢谢!
- Android进程间通信(IPC)之Messenger
- android-----IPC进程间通信之Messenger
- Android之进程间通信(IPC)-Messenger
- Android IPC 进程间通信机制之 Messenger
- android进程间通信ipc Messenger (一)
- 随笔Android IPC进程通信之——Messenger
- 安卓IPC(进程间通信)之Messenger基本使用
- android进程间通信之Messenger
- Android进程间通信之Messenger
- Android进程间通信之使用Messenger
- Android进程间通信之Messenger浅析
- Android进程间通信之使用Messenger
- 初识Android进程间通信之---Messenger
- Android进程间通信之Messenger
- Android 进程间通信之Messenger
- android—进程间通信之Messenger
- Android 进程间通信之使用Messenger
- Android进程间通信之使用Messenger
- 链接不过:undefined symbol
- adobe reader 怎么添加书签
- nested exception is org.apache.ibatis.exceptions.PersistenceException:报错解决。
- hdu
- Linux CentOS6 64位升级3.1内核的方法记录
- Android之进程间通信(IPC)-Messenger
- AWS S3 Not Allowed (Service: Amazon S3; Status Code: 405; Error Code: 405 Not Allowed; Request ID: n
- Android自定义组合控件
- 【插件-ActiveX】Visual Studio 中调试ActiveX控件
- Sparql查询实例
- Quartz动态定时器
- C++ 左值、右值、右值引用
- 自定义view(一):onMeasure
- UISlider用法和UIProgressView用法