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

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

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

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

其实基于消息的进程通信就是客户端通过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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值