Android进程间通信(3)-Messenger实现

来源:互联网 发布:seo英语编辑 编辑:程序博客网 时间:2024/06/03 19:04

前面两篇文章中已经介绍了两种实现进程间通信的方式,那是不是只有这两种方式实现进程间通信呢?当然不是,还有更好的实现方式,那就是Messenger。本篇文章将带领大家一起来学习下Messenger.

  • 基于aidl实现的进程通信
  • 基于纯代码实现的进程通信

没有看我写的上面两篇文章的同学,建议先去看下上面两篇文章,以更好的理解。

什么是基于消息的进程通信?
这里写图片描述
该图片是引用自弘扬大神的博客

其实基于消息的进程通信就是客户端通过Handler发送一条Message,服务端收到这条Message然后获取到客户端的值,服务端进行处理,再将结果封装成Message传递给客户端。通过这种方式实现aidl有什么好处呢?

  • 不用再写aidl文件了(很多同学一提到aidl就头疼)
  • 基于Message,这个大家已经很熟悉了

接下来我们通过代码详细的介绍下。

1,服务端,我们定义一个MessengerService.java的Service,代码如下:

package com.wms.github.aidl.server;import android.app.Service;import android.content.Intent;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.util.Log;/** * Created by 王梦思 on 2017/5/25. */public class MessengerService extends Service {    private static final String TAG = "MessengerService";    private Messenger messenger = new Messenger(new Handler() {        @Override        public void handleMessage(Message clientMsg) {            if (clientMsg.what == 0x001) {                //注意这个里clientMsg是客户端发送过来的消息                Bundle bundle = (Bundle) clientMsg.obj;                String str = bundle.getString("str");                str = str.toUpperCase();                //服务端处理完逻辑后,将数据通过Messeage的方式传递给客户端                Message message = Message.obtain();                Bundle sendBundle = new Bundle();                sendBundle.putString("str", str);                message.obj = sendBundle;                message.what = 0x001;                try {                    //将消息发送到客户端                    clientMsg.replyTo.send(message);                } catch (RemoteException e) {                    e.printStackTrace();                }            }            super.handleMessage(clientMsg);        }    });    @Override    public IBinder onBind(Intent intent) {        Log.e(TAG, "onBind...");        //这里不能返回null,必须要返回我们创建的Binder对象        return messenger.getBinder();    }    @Override    public boolean onUnbind(Intent intent) {        Log.e(TAG, "onUnbind...");        return super.onUnbind(intent);    }    @Override    public void onStart(Intent intent, int startId) {        Log.e(TAG, "onStart...");        super.onStart(intent, startId);    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e(TAG, "onStartCommand...");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onCreate() {        Log.e(TAG, "onCreate...");        super.onCreate();    }    @Override    public void onDestroy() {        Log.e(TAG, "onDestroy...");        super.onDestroy();    }}

服务端就一个Service,可以看到代码相当的简单,只需要去声明一个Messenger对象,然后onBind方法返回messenger.getBinder();
然后坐等客户端将消息发送到handleMessage想法,根据message.what去判断进行什么操作,然后做对应的操作,最终将结果通过 clientMsg.replyTo.send(),这里注意一定要调用clientMsg.replyTo.send()去发送消息,不然客户端接收不到。

注册MessengerService

<service            android:name="com.wms.github.aidl.server.MessengerService"            android:exported="true">            <intent-filter>                <action android:name="com.wms.github.aidl.server.MessengerService"/>                <category android:name="android.intent.category.DEFAULT"/>            </intent-filter>        </service>

2,客户端。在客户端我新建一个MessengerActivity.java,代码如下:

package com.wms.github.aidl.client;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.util.Log;import android.view.View;import android.widget.EditText;/** * Created by 王梦思 on 2017/5/25. */public class MessengerActivity extends MainActivity {    private EditText mEditText;    private Messenger mService;    private Messenger clientMessenger = new Messenger(new Handler() {        @Override        public void handleMessage(Message msg) {            if (msg.what == 0x001) {                Bundle bundle = (Bundle) msg.obj;                mEditText.setText(bundle.getString("str"));            }            super.handleMessage(msg);        }    });    private ServiceConnection mServiceConn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            //当绑定成功后调用            Log.e("MainActivity", "onServiceConnected...");            mService = new Messenger(service);        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.e("MainActivity", "onServiceDisconnected...");        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mEditText = (EditText) findViewById(R.id.id_edittext);        findViewById(R.id.bind).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                bindService();            }        });        findViewById(R.id.unbind).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                unBindService();            }        });        findViewById(R.id.invokeServer).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                invokeServer();            }        });    }    /**     * 绑定服务     */    public void bindService() {        Intent intent = new Intent();        intent.setAction("com.wms.github.aidl.server.MessengerService");        //Android 5.0以上必须要加这句代码,不然报错        intent.setPackage("com.wms.github.aidl.server");        bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);    }    public void unBindService() {        unbindService(mServiceConn);    }    public void invokeServer() {        String inputStr = mEditText.getText().toString().trim();        try {            Message message = Message.obtain();            message.what = 0x001;            Bundle bundle = new Bundle();            bundle.putString("str",inputStr);            message.obj = bundle;            //将消息的回应设置为clientMessenger,这样客户端发送消息就能在客户端收到了。            message.replyTo = clientMessenger;            mService.send(message);        } catch (RemoteException e) {            //这里会抛出远程异常            e.printStackTrace();        }    }}

布局文件和上篇文章中一样。

MessengerActivity.java中代码也很简单,就是绑定一个服务,然后再onServiceConnect中实例化一个Messenger,这个Messenger和MessengerActivity中属性clientMessenger不一样,因为这个Messenger实例化的时候把Binder驱动传递进来了。所以当客户端调用mService.send(message); 后,服务端将会收到客户端传递过来的数据,服务端处理完之后,返回到Client端的clientMessenger中的Handler的handleMessage方法中,这样就完成了客户端和服务端的通信。

效果图:
这里写图片描述

当我们点击调用服务端转换后,服务端就把大写字母回传给客户端。以上就是简单的Messenger的使用,肯定很多人有疑问,为什么这样可以实现进程间的通信呢?下面我将带领大家一起来从源码的角度来看看。

1,先分析服务端,服务端中onBind()方法里面我们返回了messenger.getBinder(); 很简单,就一行代码,我们进入Messenger的内部看下getBinder内部到底做了什么事情

/**     * Retrieve the IBinder that this Messenger is using to communicate with     * its associated Handler.     *      * @return Returns the IBinder backing this Messenger.     */    public IBinder getBinder() {        return mTarget.asBinder();    }

getBinder方法也很简单,也就一行代码。这里mTarget是什么呢?查看下源码,private final IMessenger mTarget; 可以看出mTarget是一个IMessenger对象,mTarget赋值是在我们实例化clientMessenger对象的时候Messenger构造方法里面。我们再来看看Messenger的构造方法

/**     * Create a new Messenger pointing to the given Handler.  Any Message     * objects sent through this Messenger will appear in the Handler as if     * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had     * been called directly.     *      * @param target The Handler that will receive sent messages.     */    public Messenger(Handler target) {        mTarget = target.getIMessenger();    }

继续跟进到Handler内部的getImessenger方法

final IMessenger getIMessenger() {        synchronized (mQueue) {            if (mMessenger != null) {                return mMessenger;            }            mMessenger = new MessengerImpl();            return mMessenger;        }    }

恍然大悟,原来mTarget其实是一个MessengerImpl对象。再回到Messenger中的getBinder方法,其实就是调用了MessengerImpl内部的asBinder方法,我们进入到MessengerImpl中的asBinder中看看其内部做了什么事情。

MessengerImpl原来是继承自IMessenger.Stub,是不是很熟悉?这不又回到了我们前面的文章中通过aidl实现进程通信的了么?原来Android内部已经帮我们实现了一个IMessenger.aidl文件,这个文件位于framework中的platform_frameworks_base/core/java/android/os/IMessenger.aidl,大家可以下载framework源代码去查看下。由于aidl代码较少,我下面贴出IMessenger.aidl内部代码如下:

package android.os;import android.os.Message;/** @hide */oneway interface IMessenger {    void send(in Message msg);}

哇,好简答,就一个send方法,send方法里面传递的是一个Message对象。所以这一切又回到了我们前面所说的aidl进行进程通信的内容了。如果不明白的可以看我之前写过的一篇文章 基于aidl实现的进程通信

2,接下来我们分析下客户端源代码
当客户端调用绑定服务的时候,会调用onServiceConnect方法

private ServiceConnection mServiceConn = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            //当绑定成功后调用            Log.e("MainActivity", "onServiceConnected...");            mService = new Messenger(service);        }        @Override        public void onServiceDisconnected(ComponentName name) {            Log.e("MainActivity", "onServiceDisconnected...");        }    };

在onServiceConnected中我们实例化了一个Messenger,并且传递了一个IBinder对象,这个IBinder对象就是一直说的Binder驱动。我们进入Messenger这个构造函数中看看:

/**     * Create a Messenger from a raw IBinder, which had previously been     * retrieved with {@link #getBinder}.     *      * @param target The IBinder this Messenger should communicate with.     */    public Messenger(IBinder target) {        mTarget = IMessenger.Stub.asInterface(target);    }

是不是又很熟悉?这不就是我们在 基于aidl实现的进程通信 中onSeviceConnect方法实现的一样么?

综上分析客户端和服务端的源代码,其实和我们写aidl完全一样,没有任何区别,Messenger底层其实就是基于aidl来实现的进程通信,只是Android内部已经给我们写好了一个IMessnger.aidl文件,不需要我们手动实现了。

到此,我们就已经分析完了源码了,如果还是不明白的同学建议去翻看下Messenger的源码,并不复杂,到此Android中实现进程通信的常用方式已经介绍完了。

代码传送门 : http:github.com/wms1993/blog_aidl_demo