天天看点

Android进程间通信之Messenger浅析

上篇我们讲述了进程间通信在Android中的一种独有方式Binder,建议不了解的朋友先去看一下这篇文章,因为我们今天要讲进程间的另外一种通信方式Messenger也是基于Binder的,主不过Google给我们封装好了,可以不使用AIDL就可以简单快速的实现。上篇文章链接:http://blog.csdn.net/u014366923/article/details/49887515
好,接下来我们就看看如何使用Messenger来实现。首先来看一下我们今天要学习的知识:
           

**1. Messenger是什么;

2. Android中Messenger的简单应用;

3. Messenger原理是什么,Messenger源码解析。**

一、Messenger概念:

先来看一张图

Android进程间通信之Messenger浅析

通过这张图我们可以很清楚的了解到了Messenger的通信模型。可以看到,我们可以在客户端发送一个Message给服务端,在服务端的handler中会接收到客户端的消息,然后进行对应的处理,处理完成后,再将结果等数据封装成Message,发送给客户端,客户端的handler中会接收到处理的结果。

其实说白了,它就是封装了Binder,我们不必关系Binder,通过Handler来通信的一种方式。

二、Messenger在Android中的简单应用:

下面我们来看一个小例子,模仿微信聊天,做一个智能机器人的聊天demo。在这个例子中我们使用了当下比较流行的RecyclerView代替传统的ListView。用SwipeRefreshLayout来实现下拉刷新功能。都是Google原生的控件,还是比较综合的一个小案例。

好,我们先来看一下服务端的源码:

public class MyService extends Service{

    public static final String SERVICE_KEY = "service_key";

    private HandlerThread handlerThread = new HandlerThread("service_handler_thread");

    private MyHandler handler;
    private Messenger messenger;

    @Override
    public void onCreate() {
        super.onCreate();
        handlerThread.start();
        handler = new MyHandler(handlerThread.getLooper());
        messenger = new Messenger(handler);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }


    class MyHandler extends Handler{

        public MyHandler(Looper looper){
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Bundle obj = (Bundle) msg.obj;
            obj.setClassLoader(getClass().getClassLoader());
            MessageBean messageBeanFromClient = (MessageBean) obj.getParcelable(SERVICE_KEY);
            if(messageBeanFromClient == null){
                return;
            }
            Message message = Message.obtain();

            Bundle bundle = new Bundle();

            MessageBean messageBeanToClient = new MessageBean();
            if ("第一次".equals(messageBeanFromClient.getContent())){
                messageBeanToClient.setContent("您好,我是小智");
            }else {
                messageBeanToClient.setContent("您好,"+messageBeanFromClient.getContent());
            }
            messageBeanToClient.setClient(false);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            messageBeanToClient.setDate(simpleDateFormat.format(new Date()));
            bundle.putParcelable(MainActivity.CLIENT_KEY,messageBeanToClient);
            message.obj = bundle;
            try {
                msg.replyTo.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}
           

我们来简单的读一下源码,首先继承自Android四大组件之一的Service组件,这个没什么好说的,别忘了在AndroidManifest.xml文件中注册我们的服务,在注册的时候不要忘记

android:process

属性,若是没有这个属性,那我们的服务就会和客户端在一个进程中,也就谈不上进程间通信了。好,继续来分析源码,可以看到,服务端有一个Messenger类型的对象,在构造过程中我们传递了一个Handler对象。在Handler对象的handleMessage中我们来处理客户端发给我们的消息,并且再发回给客户端。其实就是:服务端中有一个依赖于Handler的Messenger的对象,通过Handler消息循环模型,Messenger可以发送消息给客户端。在

onBind

方法中可以看到

return messenger.getBinder();

是不是突然明白点什么了呢。。。。。。

客户端源码:

public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener {

    public static final String CLIENT_KEY = "client_key";
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private RecyclerView mRecyclerView;
    private EditText et_content;
    private Messenger mService;
    private ArrayList<MessageBean> list;
    private MessageAdapter messageAdapter;

    private boolean isConnet = false;

    private Messenger  mMessenger = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Bundle obj = (Bundle) msg.obj;
            obj.setClassLoader(getClass().getClassLoader());
            list.add((MessageBean) obj.getParcelable(CLIENT_KEY));
            messageAdapter.notifyDataSetChanged();
            mRecyclerView.smoothScrollToPosition(list.size() - );
        }
    });

    private ServiceConnection serviceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isConnet = true;
            mService = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };
    private LinearLayoutManager mLayoutManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        StatusBarCompat.compat(this,getResources().getColor(R.color.colorPrimaryDark));
        initView();
        bindService();
   }

    private void bindService() {
        Intent intent = new Intent(this,MyService.class);
        bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
    }

    private void initView() {
        mSwipeRefreshLayout = (SwipeRefreshLayout) this.findViewById(R.id.swipe_refresh_layout);
        mRecyclerView = (RecyclerView) this.findViewById(R.id.recycler_view);
        mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary, R.color.colorPrimaryDark,R.color.colorAccent);
        mSwipeRefreshLayout.setOnRefreshListener(this);
        mSwipeRefreshLayout.setProgressViewOffset(false, , (int) TypedValue
                .applyDimension(TypedValue.COMPLEX_UNIT_DIP, , getResources()
                        .getDisplayMetrics()));
        mSwipeRefreshLayout.setRefreshing(true);
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//        mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL_LIST));
        Toolbar mToolBar = (Toolbar) this.findViewById(R.id.toolbar);
        mToolBar.setTitle("智能聊天机器人");
        mToolBar.setTitleTextColor(Color.WHITE);
        et_content = (EditText) this.findViewById(R.id.edit_text_content);
        list = new ArrayList<MessageBean>();
        messageAdapter = new MessageAdapter(this,list,mRecyclerView);
        mRecyclerView.setAdapter(messageAdapter);
    }

    @Override
    public void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                sendMessage("第一次");
                mSwipeRefreshLayout.setRefreshing(false);
            }
        },);
    }

    public void sendMessageToService(View view){
        String content = et_content.getText().toString().trim();
        if (isConnet && !TextUtils.isEmpty(content)) {
            MessageBean m = sendMessage(content);
            list.add(m);
            messageAdapter.notifyDataSetChanged();
            et_content.setText("");
            mRecyclerView.smoothScrollToPosition(list.size() - );
            //InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
//            inputManager.hideSoftInputFromWindow(et_content.getWindowToken(),0);
        }
    }

    @Nullable
    private MessageBean sendMessage(String content) {
        Message message = Message.obtain();
        MessageBean messageBean = new MessageBean();
        messageBean.setContent(content);
        messageBean.setClient(true);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        messageBean.setDate(simpleDateFormat.format(new Date()));

        Bundle bundle = new Bundle();
        bundle.putParcelable(MyService.SERVICE_KEY, messageBean);
        message.obj = bundle;
        try {
            message.replyTo = mMessenger;
            mService.send(message);
            return messageBean;
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return null;
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        isConnet = false;
        unbindService(serviceConnection);
    }

    @Override
    public void onRefresh() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
            }
        },);
    }
}
           

客户端源码比较简单了,我们来重点看几段代码:

private void bindService() { Intent intent = new Intent(this,MyService.class); bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE); }

绑定我们的服务端Service,相信大家都懂得,在

private ServiceConnection serviceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isConnet = true;
            mService = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }; 
           

在这里我们看到又创建了一个Messenger对象,我滴神额,咋又创建了一个,仔细一看,构造方法参数还不一样,服务端我们创建的时候是传入了一个Handler对象,这里好像是一个IBinder对象诶 ~(≧▽≦)/~ 泪奔中……, 先不要慌,我们继续来看代码,细心的朋友可以看到其实我们客户端是有两个Messenger对象的,oh my god!!! 。加上服务端的不是又三个对象吗,是的 确实是有三个Messenger对象。我们来梳理一下逻辑吧,可能有些朋友要疯…………o(>﹏<)o。

按照上面的模型图,要想实现这样的通信方式,服务端和和客户端必须要各自有一个Messenger对象才行,要不然没法发送消息啊!客户端只有把自己的Messenger对象给服务端,服务端把自己的Messenger对象给客户端,这样在双方中都会有彼此的引用对象,才可以发送消息,是不是呢~,至于为什么客户端要有两个Messenger对象,是因为客户端是主动发起方,它必须要先拿到服务端Messenger对象才行,这里你可以把这个Messenger对象理解为服务端的Messenger。

三、源码解析:

好,我们来看一下Messenger的内部源码到底什么怎样的,首先看一下通过Handler对象构建的构造方法,也就是服务端的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对象返回了一个mTarget对象,那mTarget对象是什么呢,我们找到mTarget的声明

private final IMessenger mTarget;

它是一个IMessenger类型的对象。我们继续看一下target.getIMessenger();内部是什么样的,继续跟进去:

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

这里创建了一个 MessengerImpl类型的对象,来看看MessengerImpl是什么:

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

它是Handler的一个内部类,实现了

IMessenger.Stub

接口,等等…… 我怎么看着这么眼熟呢,没错,我们之前用Binder的时候也有一个类实现了xxxxx.Stub接口。莫非~没错,你想的没错,它和我们之前用的是一样的。它同样对应一个AIDL文件。再回想一下我们服务端的onBinder方法,

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

这下明白了吧,和我们之前用的Binder不是一样嘛,对不对,嘿嘿,是不是有种~。。。。。。,

我们继续看一下客户端源码:

我们重点看一下serviceConnection中的

@Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isConnet = true;
            mService = new Messenger(service);
        }
           

看一下用IBinder 对象创建的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);
    }
           

这里可以看到和我们之前写的几乎一模一样,无非就是Messenger更进一步封装了而已。

最后我们来看一下发送消息的过程:

无论是服务端还是客户端发送消息都是用的Messenger的send方法,

/**
     * Send a Message to this Messenger's Handler.
     * 
     * @param message The Message to send.  Usually retrieved through
     * {@link Message#obtain() Message.obtain()}.
     * 
     * @throws RemoteException Throws DeadObjectException if the target
     * Handler no longer exists.
     */
    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }
           

再调用的IMessenger的send方法,其实就是Handler里面创建的MessengerImpl的send方法,我们看到在MessengerImpl的send方法里面调用了Handler的sendMessage方法。这样就可以通过Handler的消息循环模型来接收,发送消息了,进而实现了进程间的通信。说白了,Messenger通信方式就是Handler+Binder。

最后来一张效果图:

Android进程间通信之Messenger浅析

源码地址:

https://github.com/qqxliufeng/MessengerTestProject