天天看點

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