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

来源:互联网 发布:java中flag的用法 编辑:程序博客网 时间:2024/05/16 07:50

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就可以接收到消息了。

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

0 0