Android 进阶——轻量级跨进程传递Message利器Messenger详解

引言

作为Android 开发者相信我们对于消息机制一定非常熟悉,对于进程内使用Handler处理Message 也一定了如执掌,而如果让你使用最简洁的方式实现进程间通信,也许有相当一部分初学者想到的是用AIDL自己实现,诚然思路是对的,但是还有更简单的机制供你使用。

一、Messenger 概述

Messenger是基于消息Message的传递的一种轻量级IPC进程间通信方式(通过在一个进程中创建一个指向Handler的Messenger,并将该Messenger传递给另一个进程),当然本质就是对Binder的封装(也是通过AIDL实现的 )。通过Messenger可以让我们可以简单地在进程间直接使用Handler进行Message传递,跨进程是通过Binder(AIDL实现),而消息发送是通过Handler#sendMessage方法,而处理则是Handler#handleMessage处理的;当然除了Handler之外还可以是自定义的相关的某些IBinder接口,简而言之,Messenger的跨进程能力是由构造时关联的对象提供的

二、Messenger 源码解析

Messenger 实现了Parcelable接口,意味着自身可以跨进程传递,同时持有IMessenger 接口引用(一个Binder对象)意味着拿到这个Binder对象就可以跨进程使用。Messenger 只是把IMessenger接口包装起来并通过Binder进行跨进程传递,真正的核心能力提供者是IMessenger的实现类——android.os.Handler.MessengerImpl。

package android.os;

/**
 * Reference to a Handler, which others can use to send messages to it.
 * This allows for the implementation of message-based communication across
 * processes, by creating a Messenger pointing to a Handler in one process,
 * and handing that Messenger to another process.
 */
public final class Messenger implements Parcelable {
    private final IMessenger mTarget;

    /**
     * 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();
    }

    /**
     * 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);
    }
    
    /**
     * Send a Message to this Messenger's Handler.
     * 
     * @param message The Message to send.  Usually retrieved through
     * {@link Message#obtain() Message.obtain()}.
     */
    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }
    
    /**
     * 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();
    }
    
    public boolean equals(Object otherObj) {
        if (otherObj == null) {
            return false;
        }
        try {
            return mTarget.asBinder().equals(((Messenger)otherObj)
                    .mTarget.asBinder());
        } catch (ClassCastException e) {
        }
        return false;
    }

    public int hashCode() {
        return mTarget.asBinder().hashCode();
    }
    
    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeStrongBinder(mTarget.asBinder());
    }

    public static final Parcelable.Creator<Messenger> CREATOR
            = new Parcelable.Creator<Messenger>() {
        public Messenger createFromParcel(Parcel in) {
            IBinder target = in.readStrongBinder();
            return target != null ? new Messenger(target) : null;
        }

        public Messenger[] newArray(int size) {
            return new Messenger[size];
        }
    };

    public static void writeMessengerOrNullToParcel(Messenger messenger,
            Parcel out) {
        out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
                : null);
    }

    public static Messenger readMessengerOrNullFromParcel(Parcel in) {
        IBinder b = in.readStrongBinder();
        return b != null ? new Messenger(b) : null;
    }
}

1、IMessenger接口

IMessenger是通过AIDL 自动生成的,一般在原生Android系统中I前缀的都是AIDL接口对应的实现类。对应的Messenger.aidl:

package android.os;

parcelable Messenger;

而IMessenger.aidl里就定义了一个入参为Message的方法 send(in Message msg)

package android.os;

import android.os.Message;

/** @hide */
oneway interface IMessenger {
    void send(in Message msg);
}

IMessenger.aidl对应的AIDL实现类:

public interface IMessenger extends android.os.IInterface {
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements
            android.os.IMessenger {
        private static final java.lang.String DESCRIPTOR = "android.os.IMessenger";

        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        public static android.os.IMessenger asInterface(...}

        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data,
                android.os.Parcel reply, int flags)
                throws android.os.RemoteException {...}

        private static class Proxy implements android.os.IMessenger {...}

    public void send(android.os.Message msg)
            throws android.os.RemoteException;
}

IMessenger就是一个Binder 接口只提供了一个方法——send 用于跨进程发送消息Message。

2、Messenger 主要方法

2.1、Messenger(Handler target)

 public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

通过Handler构造Messenger时,就是调用了传入的Handler#getIMessenger()方法得到单例构造的MessengerImpl实例并初始化mTarget。

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

继续往下追

 private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

本质就是通过Handler#sendMessage完成通信。

2.2、Messenger(IBinder target)

而通过IBinder对象构造Messenger时,就是把传入的IBinder对象“转成”MessengerImpl实例并初始化mTarget成员变量。

并非简单地直接强转而是先检索,如果已经创建过了就直接返回IBinder对应的代理对象,否则创建对应的代理对象再返回,预知详情请后续关注Binder系列文章。

public Messenger(IBinder target) {
    mTarget = IMessenger.Stub.asInterface(target);    
}

2.3、send(Message message)

前面分析了send方法本质就是调用Handler#sendMessage方法,这也解释了为什么我们在服务端和客户端都需要创建Handler,因为需要在Handler去处理接收到的消息。

public void send(Message message) throws RemoteException {
        mTarget.send(message);//MessengerImpl#send
    }

三、Messenger的使用

Messenger 基于Binder可以跨进程通信,为了方便我简单的把一个进程称之为服务端进程,另一个称之为客户端进程

1、首先在服务端定义一个Messenger对象

Messager.replyTo指向的客户端的Messenger,而Messenger又持有客户端的一个IBinder对象(即MessengerImpl),服务端正是利用这个IBinder对象做的与客户端的通信。

  • 创建一个Handler
  • 使用Handler初始化构建Messenger
package com.crazymo.messenger.rawmessenger;

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;

public class MessengerService extends Service {
    public final static String TAG = "MessengerIPC";
    public final static String KEY_NAME = "Name";
    public final static String KEY_RESP = "Response";
    public final static int MSG_WHAT_HELLO = 100;
    public final static int MSG_WHAT_RESP = 1001;
    /**
     * 一个用于跨进程的序列化对象,包裹着IMessenger AIDL接口
     */
    private static final Messenger messenger = new Messenger(new MessengerServerHandler());

    private static class MessengerServerHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            doHandleMessage(msg);
        }
    }

    /**
     * 处理其他进程发过来的消息
     * @param msg
     */
    private static void doHandleMessage(Message msg) {
        if (msg != null) {
            String ret = "hello ";
            //接收客户端的消息并处理
            if (msg.what == MSG_WHAT_HELLO) {
                Log.e(TAG, "receive msg from client=" + msg.getData().getString(KEY_NAME));
                try {
                    Thread.sleep(1_000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ret += msg.getData().getString(KEY_NAME);
                //把处理结果封装到Message返回给客户端
                Message reply = Message.obtain(null, MSG_WHAT_RESP);
                Bundle bundle = new Bundle();
                bundle.putString(KEY_RESP, ret);
                reply.setData(bundle);
                try {
                    //msg.replyTo @ android.os.Messenger类型,Messager.replyTo指向的客户端的Messenger,而Messenger又持有客户端的一个Binder对象(MessengerImpl)。服务端正是利用这个Binder对象做的与客户端的通信。
                    if (msg.replyTo != null) {
                        msg.replyTo.send(reply);
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        } else {
            Log.e(TAG, "handle client empty msg");
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        //返回Messenger的IBinder对象,当bindService 执行时候就会触发该回调,就可以拿到服务端的IBinder对象
        return messenger.getBinder();
    }
}

然后就在传入Handler#handleMessage 方法中实现处理消息的逻辑,至此一个远程Service实现完毕。

2、客户端使用Messenger

  • 定义一个Handler 用于发送Message
  • 初始化Messenger对象
package com.crazymo.messenger;

import android.annotation.SuppressLint;
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.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.crazymo.messenger.aidl.MyMessengerService;
import com.crazymo.messenger.rawmessenger.MessengerService;

public class MainActivity extends AppCompatActivity {
    private final static String TAG="MainActivity";
    /***********************1、Messenger 方式****************************/
    private Messenger mServer;
    private ServiceConnection connMessenger =new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mServer=new Messenger(service);//把返回的IBinder对象初始化Messenger
            Log.e(MessengerService.TAG, "MessengerService Connected!");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private final Handler handlerClient =new Handler(){
        @SuppressLint("HandlerLeak")
        @Override
        public void handleMessage(Message msg) {
            if(msg!=null && msg.what== MessengerService.MSG_WHAT_RESP){
                String resp=msg.getData().getString(MessengerService.KEY_RESP);
                Log.e(MessengerService.TAG, "resp from server="+resp);
            }
        }
    };

    //为了接收服务端的回复,客户端也需要准备一个接收消息的Messenger 和Handler
    private final Messenger clientMessenger=new Messenger(handlerClient);

    private void bindMessengerService() {
        Intent intent=new Intent(this,MessengerService.class);
        bindService(intent, connMessenger, Context.BIND_AUTO_CREATE);

    }

    public void sendByMessenger(View view) {
        Message msg=Message.obtain(null,MessengerService.MSG_WHAT_HELLO);
        Bundle data=new Bundle();
        data.putString(MessengerService.KEY_NAME,"CrazyMo_");
        msg.setData(data);
        //Client 发信时指定希望回信人,把客户端进程的Messenger对象设置到Message中
        msg.replyTo=clientMessenger;
        try {
            mServer.send(msg);//跨进程传递
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /***********************2、MyMessenger AIDL方式****************************/
    private IMyMessenger myInterface;
    private ServiceConnection connAidl = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myInterface = IMyMessenger.Stub.asInterface(service);
            Log.i(TAG, "MyMessenger 连接Service 成功");
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "连接Service失败");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindMessengerService();
        bindMyMessengerService();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connMessenger);
        unbindService(connAidl);
    }

    public void sendByMyMessenger(View view) {
        try {
            String ret=myInterface.send("hello server my MyMessenger");
            Log.i(TAG, "myInterface.send的结果="+ret);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void bindMyMessengerService() {
        Intent intent=new Intent(this, MyMessengerService.class);
        bindService(intent, connAidl, Context.BIND_AUTO_CREATE);
    }
}

3、传统AIDL实现 VS Messenger

// IMyMessenger.aidl
package com.crazymo.messenger;

interface IMyMessenger {

    String send( String aString);
}

public class MyMessengerService  extends Service {

    private static final String TAG="MyMessengerService";
    private MyMessengerBinder mBinder=new MyMessengerBinder();
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    private static class MyMessengerBinder extends IMyMessenger.Stub{
        @Override
        public String send(String aString) throws RemoteException {
            String ret="reply to client"+aString;
            Log.e(TAG,"received str from c:"+aString);
            return ret;
        }
    }
}

两者对比你会发现以原程服务的形式使用传统AIDL和Messenger大同小异,区别仅仅是在于初始化的时候,当onServiceConnected方法回调时初始化构造远程Binder对象的方式有所差别,剩下的基本一模一样。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Avro是一个轻量级的数据序列化框架,同时也提供了RPC功能。Avro提供了一个基于JSON的schema定义文件来描述数据结构,使得Avro能够支持动态的数据类型。Avro还提供了一个名为avro-rpc的模块,用于实现基于Avro的RPC。 下面我们来对avro-rpc行性能测试。我们将使用Python 3.7作为客户端和服务端编程语言,并使用Apache Bench来行压力测试。 首先,我们需要安装avro和avro-rpc模块: ``` pip install avro pip install avro-rpc ``` 接下来,我们编写一个简单的RPC服务端程序: ```python import avro.protocol import avro.ipc import socket PROTOCOL = avro.protocol.parse(open("test.avpr").read()) class RpcServer(object): def __init__(self, host, port): self.server = avro.ipc.HTTPServer(self.handle_request) self.server.add_listener((host, port)) def handle_request(self, request, protocol): message_name = request.message_name request_params = request.request_params print("Received request: {} {}".format(message_name, request_params)) if message_name == "ping": return "pong" elif message_name == "echo": return request_params else: raise avro.AvroRemoteException("Unknown message: {}".format(message_name)) def serve_forever(self): self.server.start() self.server.join() if __name__ == "__main__": server = RpcServer("localhost", 8080) server.serve_forever() ``` 这个RPC服务端程序会监听localhost的8080端口,并实现了两个RPC方法:ping和echo。当客户端调用ping方法时,服务端会返回字符串“pong”;当客户端调用echo方法时,服务端会返回客户端传递的参数。 接下来,我们编写一个简单的RPC客户端程序: ```python import avro.protocol import avro.ipc import socket PROTOCOL = avro.protocol.parse(open("test.avpr").read()) class RpcClient(object): def __init__(self, host, port): self.transceiver = avro.ipc.HTTPTransceiver((host, port)) self.requestor = avro.ipc.Requestor(PROTOCOL, self.transceiver) def ping(self): return self.requestor.request("ping", []) def echo(self, message): return self.requestor.request("echo", [message]) if __name__ == "__main__": client = RpcClient("localhost", 8080) print(client.ping()) print(client.echo("Hello, world!")) ``` 这个RPC客户端程序会连接到localhost的8080端口,并调用服务端实现的ping和echo方法。 接下来,我们使用Apache Bench来行压力测试: ``` ab -n 10000 -c 10 http://localhost:8080/ ``` 这个命令会模拟10个并发连接,总共发送10000个请求。我们可以通过修改-n和-c参数来改变测试规模。 测试结果如下: ``` Server Software: Server Hostname: localhost Server Port: 8080 Document Path: / Document Length: 4 bytes Concurrency Level: 10 Time taken for tests: 7.194 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 1830000 bytes HTML transferred: 40000 bytes Requests per second: 1390.36 [#/sec] (mean) Time per request: 7.194 [ms] (mean) Time per request: 0.719 [ms] (mean, across all concurrent requests) Transfer rate: 248.18 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.3 0 14 Processing: 1 7 2.3 7 24 Waiting: 1 7 2.3 7 24 Total: 1 7 2.3 7 24 Percentage of the requests served within a certain time (ms) 50% 7 66% 8 75% 8 80% 8 90% 10 95% 12 98% 15 99% 17 100% 24 (longest request) ``` 从测试结果中可以看出,avro-rpc在处理10000个请求时,平均每个请求处理时间为7.194毫秒。每秒处理请求数为1390.36,处理速度较快,而且没有出现失败的请求。因此,我们可以认为avro-rpc是一个性能良好的轻量级RPC框架。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值