Android之进程间通信(IPC)-Messenger

文章连接:http://blog.csdn.net/qq_16628781/article/details/70087623

知识点:

  1. 进程间通信的几种方式;
  2. Android中利用messenger信使进行通信;
  3. 新名词记录{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就可以接收到消息了。

以上就是所有内容,如有任何问题,请及时与我联系,谢谢!

更多相关文章

  1. java线程实现与进程(二)
  2. 使用线程设置后台进程以处理Android中的工作
  3. 理解Android的本地Service和跨进程Service
  4. android init进程分析 ueventd — 设备节点的创建、固件更新过
  5. Linux上杀死eclipse进程
  6. Windows中结束占用某个端口的进程
  7. 关于Hadoop查看进程时jps命令出现Error: could not find libjava

随机推荐

  1. 一步步从头搭建 Vue 开发环境
  2. 8 个你不知道的 DOM 功能[每日前端夜话0x
  3. 从输入 URL 到展现涉及哪些缓存环节(非常
  4. 一笔订单,但是误付了两笔钱!这种重复付款异
  5. 收款神器!解读聚合收款码背后的原理|原创
  6. LoRa基站网关-室外型
  7. python入门教程12-04 (python语法入门之进
  8. Redhat Openshift 4.6 单机版安装指南(1)
  9. Angular v8 发布!来看看有什么新功能[每日
  10. 快取,陣列,程式,这些台湾的计算机术语,你知道