• Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- Messenger


    Messenger类实际是对Aidl方式的一层封装。本文只是对如何在Service中使用Messenger类实现与客户端的通信进行讲解,对Messenger的底层不做说明。阅读Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- AIDL了解如何使用Aidl的方式实现服务端与客户端的通信。

    在Service中使用Messenger,大部分代码还是跟Android的消息机制打交道,具体一点就是跟Handler,Message打交道。阅读Android -- Looper、Handler、MessageQueue等类之间关系的序列图了解Android的消息机制。

    服务端:

    Step 1:定义两个变量

    private Handler mMessageHandler;
    private Messenger mMessenger;

    Step 2:对两个变量进行赋值

         @Override
        public void onCreate() {
            super.onCreate();
            HandlerThread handlerThread = new HandlerThread("MessengerService");
            handlerThread.start();
            mMessageHandler = new Handler(handlerThread.getLooper(), new MyHandlerCallback());
            mMessenger = new Messenger(mMessageHandler);
        }

    这里我们使用到了HandlerThread进行辅助。而MyHandlerCallback实现了Handler.Callback接口,实现对消息的处理,完成具体操作。

    Step 3:实现Handler.Callback接口

     private class MyHandlerCallback implements Handler.Callback{
            @Override
            public boolean handleMessage(Message msg) {
                boolean delivered = false;
                switch (msg.what){
                    case MessageApi.SEND_TEXT_MSG:
                        Bundle bundle = msg.getData();
                        delivered = sendTextMessage(bundle.getString(MessageApi.MSG_TEXT_KEY));
                        break;
                    case MessageApi.SEND_PHOTO_MSG:
                        delivered = sendPhotoMessage((Bitmap) msg.obj);
                        break;
                }
                Message reply = Message.obtain();
                reply.what = MessageApi.MESSAGE_DELIVERED_MSG;
                Bundle bundle = new Bundle();
                bundle.putBoolean(MessageApi.MSG_DELIVERED_KEY, delivered);
                reply.setData(bundle);
                try {
                    // Send message back via Message.replyto
                    msg.replyTo.send(reply);
                } catch (RemoteException e) {
                    Log.e(TAG, "Error sending message reply!", e);
                }
    
                return true;
            }
        }

    这里与一般的handleMessage没多大区别,主要就是在给客户端回消息时使用到了Message.replyto。因此,可想而知,在客户端发送消息时,如果要接收服务端的消息就必须对消息指定replyto。而replyto实际也是一个Messenger实例。而服务端与客户端使用的消息代码要保持一致,因此这里我们单独用了一个类MessageApi进行存放:

    public class MessageApi {
        public static final int SEND_TEXT_MSG = 10;
        public static final int SEND_PHOTO_MSG = 20;
        public static final int MESSAGE_DELIVERED_MSG = 30;
        public static final String MSG_TEXT_KEY = "text_key";
        public static final String MSG_DELIVERED_KEY = "delivered_key";
    }

    Step 4:返回Binder实例对象到客户端。

        @Override
        public IBinder onBind(Intent intent) {
            Log.d(TAG, "onBind");
            return mMessenger.getBinder();
        }

    以上就是服务端的基本步骤了。

    服务端示例完整代码:

    package com.ldb.android.example.messengerservice.service;
    
    import android.app.Service;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.Messenger;
    import android.os.RemoteException;
    import android.support.annotation.Nullable;
    import android.util.Log;
    
    import com.ldb.android.example.messengerservice.api.MessageApi;
    
    /**
     * Created by lsp on 2016/9/2.
     */
    public class MessengerService extends Service {
        private static final String TAG = "MessengerService";
    
        private Handler mMessageHandler;
        private Messenger mMessenger;
    
        @Override
        public void onCreate() {
            super.onCreate();
            HandlerThread handlerThread = new HandlerThread("MessengerService");
            handlerThread.start();
            mMessageHandler = new Handler(handlerThread.getLooper(), new MyHandlerCallback());
            mMessenger = new Messenger(mMessageHandler);
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.d(TAG, "onBind");
            return mMessenger.getBinder();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            mMessageHandler.getLooper().quit();
        }
    
        private class MyHandlerCallback implements Handler.Callback{
            @Override
            public boolean handleMessage(Message msg) {
                boolean delivered = false;
                switch (msg.what){
                    case MessageApi.SEND_TEXT_MSG:
                        Bundle bundle = msg.getData();
                        delivered = sendTextMessage(bundle.getString(MessageApi.MSG_TEXT_KEY));
                        break;
                    case MessageApi.SEND_PHOTO_MSG:
                        delivered = sendPhotoMessage((Bitmap) msg.obj);
                        break;
                }
                Message reply = Message.obtain();
                reply.what = MessageApi.MESSAGE_DELIVERED_MSG;
                Bundle bundle = new Bundle();
                bundle.putBoolean(MessageApi.MSG_DELIVERED_KEY, delivered);
                reply.setData(bundle);
                try {
                    // Send message back via Message.replyto
                    msg.replyTo.send(reply);
                } catch (RemoteException e) {
                    Log.e(TAG, "Error sending message reply!", e);
                }
    
                return true;
            }
        }
    
        // Return true when delivered
        private boolean sendPhotoMessage(Bitmap photo) {
            // Implementation left out for brevity
            Log.d(TAG, "sendPhotoMessage");
            return true;
        }
        // Return true when delivered
        private boolean sendTextMessage(String textMessage) {
            // Implementation left out for brevity
            Log.d(TAG, "sendTextMessage: " + textMessage);
            return true;
        }
    
    }

    客户端:

    Step 1:将服务端的MessageApi类拷贝到客户端。

    Step 2:定义三个变量

        private Messenger mRemoteMessenger;
        private Messenger mReplyMessenger;
        private Handler mReplyHandler;

    Step 3:为mReplyHandler与mReplyMessenger赋值

         @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mSendButton = (Button) findViewById(R.id.send_button);
            mSendButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    sendText();
                }
            });
    
            HandlerThread handlerThread = new HandlerThread("MessageClient");
            handlerThread.start();
                mReplyHandler = new Handler(handlerThread.getLooper(), new ReplyHandlerCallback());
            mReplyMessenger = new Messenger(mReplyHandler);
        }

    与服务端类似。ReplyHandlerCallback实现了Handler.Callback接口.

    Step 4:实行Handler.Callback,处理服务端返回的消息。

        private class ReplyHandlerCallback implements Handler.Callback{
            @Override
            public boolean handleMessage(Message msg) {
                switch (msg.what){
                    case MessageApi.MESSAGE_DELIVERED_MSG:
                        Bundle bundle = msg.getData();
                        boolean delivered = (boolean) bundle.getBoolean(MessageApi.MSG_DELIVERED_KEY);
                        Log.d(TAG, "delivered: " + delivered);
                        break;
                }
                return true;
            }
        }

    Step 5:实现ServiceConnection接口,在onServiceConnected()方法中,我们获取到了服务端的代理Messenger -- mRemoteMessenger, 客户端与服务端的通信都是通过此代理来完成的。

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mRemoteMessenger = new Messenger(service);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mRemoteMessenger = null;
        }

    Step 6:bindService,从Android 5.0开始,bindService需要通过Explicit Intent。

        @Override
        protected void onResume() {
            super.onResume();
            // Since Android 5.0(Lollipop), bindService should use explicit intent.
            Intent intent = new Intent("com.ldb.android.example.messengerservice.MessengerService");
            bindService(
                    createExplicitFromImplicitIntent(this, intent),
                    this, BIND_AUTO_CREATE);
        }

    Step 7:记得unbindService。

    Step 8:发送消息,使用Bundle作为消息内容的载体,不要使用Message.obj,书中是直接使用Message.obj,但是实际操作却报错了,网上建议使用Bundle。如果希望服务端返回消息,则需要指定replyto,实际就是我们在onCreate中实例化的mReplyMessenger,因为它与mReplyHandler相关联,因此服务端通过它返回的消息最终都由mReplyHandler进行处理。

        public void sendText(){
            String textMessage = ((EditText) findViewById(R.id.message_edit_text)).getText().toString();
            Message message = Message.obtain();
            message.what = MessageApi.SEND_TEXT_MSG;
            // Can't use Message.obj
    //        message.obj = textMessage;
            // Use Bundle to load the message content.
            Bundle bundle = new Bundle();
            bundle.putString(MessageApi.MSG_TEXT_KEY, textMessage);
            message.setData(bundle);
            // Service would use replyto to send message back.
            message.replyTo = mReplyMessenger;
            try {
                mRemoteMessenger.send(message);
            } catch (RemoteException e) {
                Log.e(TAG, "Error sendText: " + message, e);
            }
        }

    以上就是客户端的基本步骤了。

    客户端完整代码:

    package com.ldb.android.example.messengerclient;
    
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.content.pm.PackageManager;
    import android.content.pm.ResolveInfo;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.Messenger;
    import android.os.RemoteException;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    
    import com.ldb.android.example.messengerclient.api.MessageApi;
    
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity implements ServiceConnection{
        private static final String TAG = "MainActivity";
    
        private Messenger mRemoteMessenger;
        private Messenger mReplyMessenger;
        private Handler mReplyHandler;
        private Button mSendButton;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mSendButton = (Button) findViewById(R.id.send_button);
            mSendButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    sendText();
                }
            });
    
            HandlerThread handlerThread = new HandlerThread("MessageClient");
            handlerThread.start();
                mReplyHandler = new Handler(handlerThread.getLooper(), new ReplyHandlerCallback());
            mReplyMessenger = new Messenger(mReplyHandler);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            // Since Android 5.0(Lollipop), bindService should use explicit intent.
            Intent intent = new Intent("com.ldb.android.example.messengerservice.MessengerService");
            bindService(
                    createExplicitFromImplicitIntent(this, intent),
                    this, BIND_AUTO_CREATE);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            unbindService(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mReplyHandler.getLooper().quit();
        }
    
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mRemoteMessenger = new Messenger(service);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mRemoteMessenger = null;
        }
    
        public void sendText(){
            String textMessage = ((EditText) findViewById(R.id.message_edit_text)).getText().toString();
            Message message = Message.obtain();
            message.what = MessageApi.SEND_TEXT_MSG;
            // Can't use Message.obj
    //        message.obj = textMessage;
            // Use Bundle to load the message content.
            Bundle bundle = new Bundle();
            bundle.putString(MessageApi.MSG_TEXT_KEY, textMessage);
            message.setData(bundle);
            // Service would use replyto to send message back.
            message.replyTo = mReplyMessenger;
            try {
                mRemoteMessenger.send(message);
            } catch (RemoteException e) {
                Log.e(TAG, "Error sendText: " + message, e);
            }
        }
    
        public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
            // Retrieve all services that can match the given intent
            PackageManager pm = context.getPackageManager();
            List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
    
            // Make sure only one match was found
            if (resolveInfo == null || resolveInfo.size() != 1) {
                return null;
            }
    
            // Get component info and create ComponentName
            ResolveInfo serviceInfo = resolveInfo.get(0);
            String packageName = serviceInfo.serviceInfo.packageName;
            String className = serviceInfo.serviceInfo.name;
            ComponentName component = new ComponentName(packageName, className);
    
            // Create a new intent. Use the old one for extras and such reuse
            Intent explicitIntent = new Intent(implicitIntent);
    
            // Set the component to be explicit
            explicitIntent.setComponent(component);
    
            return explicitIntent;
        }
    
        private class ReplyHandlerCallback implements Handler.Callback{
            @Override
            public boolean handleMessage(Message msg) {
                switch (msg.what){
                    case MessageApi.MESSAGE_DELIVERED_MSG:
                        Bundle bundle = msg.getData();
                        boolean delivered = (boolean) bundle.getBoolean(MessageApi.MSG_DELIVERED_KEY);
                        Log.d(TAG, "delivered: " + delivered);
                        break;
                }
                return true;
            }
        }
    }


    布局文件:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <EditText
            android:id="@+id/message_edit_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    
        <Button
            android:id="@+id/send_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Send"/>
    </LinearLayout>
  • 相关阅读:
    Shell学习笔记 ——第一天
    Myclipse 安装 Maven遇见的N个异常
    Myeclipse 创建 Web Maven项目
    Guava API
    String 转Map(基于Guava类库)
    Mybatis——helloWorld级程序
    redis
    listener、context、filter、servlet及其加载顺序
    junit 单元测试
    hibernate —— 树状存储
  • 原文地址:https://www.cnblogs.com/yarightok/p/5838891.html
Copyright © 2020-2023  润新知