当前位置:   article > 正文

Android跨进程通信(三):Messenger使用教程

Android跨进程通信(三):Messenger使用教程

文章目录

Android跨进程通信(一):AIDL使用教程1
Android跨进程通信(二):AIDL使用教程2
Android跨进程通信(三):Messenger使用教程
Android跨进程通信(四):AIDL源码解析
Android跨进程通信(五):Messenger源码解析

前面的文章讲述了如何通过AIDL来实现Android的跨进程通信,本篇文章来讲解如何使用Messenger来实现同样的功能。

介绍

Messenger是AIDL的封装,进程可以通过Messenger来实现通信。直接编写AIDL相当复杂,而Messenger大大简化了编写流程。

下面先介绍Messenger的基本使用方法。

准备工作

创建Messenger对象需要传入一个Handler,在这个Handler里对接收到的数据进行处理。

Handler handler = new Handler(){
	@Override
        public void handleMessage(@NonNull Message msg) {
        	...
        }
}
Messenger messenger = new Messenger();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

或者传入IBinder,这种方式是在客户端中实现的。

private class SensorConnection implements ServiceConnection{
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mSensorMessenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

发送数据方式如下。这里有两个地方容易弄混。
首先是message.replyTo = mMessenger,意思是在信封里说明谁是发送者。
其次是mRecvMessenger.send(message),A 要发送数据给 B,A用的是B的Messenger来发送。

Message message = Message.obtain();
//Bundle实现了序列化
Bundle bundle = new Bundle();
bundle.putString("name","PYJTLK");
message.setData(bundle);
message.replyTo = mMessenger;
mRecvMessenger.send(message);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

而下面这种方式是错误的,因为是跨进程通信,发送的数据必须实现序列化。

Message message = Message.obtain();
//错误,因为String类没有实现序列化,应该把数据放入Bundle中,Bundle实现了序列化。
message.obj = new String("hello");
message.replyTo = mMessenger;
mRecvMessenger.send(message);
  • 1
  • 2
  • 3
  • 4
  • 5

了解了Messenger的基本使用后,接下来就通过一个例子来讲述Messenger跨进程通信的完整流程。其中服务端提供温度传感器(模拟场景)服务,客户端绑定该服务,并通过Messenger来获取温度值。

服务端代码

首先创建一个传感器管理类,因为传感器在设备中是单例,所以这里使用单例模式。

public class SensorManager {
    private static final int CMD_GET_TEMPERATURE = 0;
    private static final int CMD_OPEN_SENSOR = 1;
    private static final int CMD_SHUT_SENSOR = 2;

    private static final String KEY_GET_TEMPERATURE_RESULT = "get result";
    private static final String KEY_OPEN_SENSOR_RESULT = "open result";
    private static final String KEY_SHUT_SENSOR_RESULT = "shut result";

    private static SensorManager sSensorManager;

    private SensorHandler mHandler;
    private Messenger mMessenger;

    private class SensorHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            try {
                Message message = Message.obtain();
                //信封内说明谁是发送者
                Messenger clientMessenger = msg.replyTo;
                Bundle bundle = new Bundle();
                message.setData(bundle);
                String result;

                switch (msg.what){
                    case CMD_GET_TEMPERATURE:
                        message.what = CMD_GET_TEMPERATURE;
                        //message.obj = new Double(...) 这种方法是不行的,因为Double类没有实现序列化,跨进程传输的类对象必须实现了序列化,比如Bundle
                        bundle.putDouble(KEY_GET_TEMPERATURE_RESULT,getTemperature());
                        message.replyTo = mMessenger;
                        //服务端发送数据,使用客户端的Messenger来发送
                        clientMessenger.send(message);
                        break;

                    case CMD_OPEN_SENSOR:
                        message.what = CMD_OPEN_SENSOR;
                        result = setTemperatureSensor(true) ? "open successfully" : "open failed";
                        //message.obj = new String("...") 这种方法是不行的,因为String类没有实现序列化,跨进程传输的类对象必须实现了序列化,比如Bundle
                        bundle.putString(KEY_OPEN_SENSOR_RESULT,result);
                        message.replyTo = mMessenger;
                        //服务端发送数据,使用客户端的Messenger来发送
                        clientMessenger.send(message);
                        break;

                    case CMD_SHUT_SENSOR:
                        message.what = CMD_SHUT_SENSOR;
                        result = setTemperatureSensor(true) ? "shut successfully" : "shut failed";
                        //message.obj = new String("...") 这种方法是不行的,因为String类没有实现序列化,跨进程传输的类对象必须实现了序列化,比如Bundle
                        bundle.putString(KEY_SHUT_SENSOR_RESULT,result);
                        message.replyTo = mMessenger;
                        //服务端发送数据,使用客户端的Messenger来发送
                        clientMessenger.send(message);
                        break;
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    private SensorManager(){
        mHandler = new SensorHandler();
        mMessenger = new Messenger(mHandler);
    }

    //手机上的传感器属于单例,因此使用单例模式
    public static SensorManager getInstance(){
        synchronized (SensorManager.class){
            if(sSensorManager == null){
                sSensorManager = new SensorManager();
            }
        }
        return sSensorManager;
    }

    public double getTemperature(){
        try {
            //假设获取温度信息是很耗时的任务
            Thread.sleep(100);
            double temperature = Math.random() * 100;
            return temperature;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return -1;
        }
    }

    public boolean setTemperatureSensor(boolean isOpen){
        try {
            //假设开关温度传感器是很耗时的操作
            Thread.sleep(100);
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }

    public Messenger getMessenger(){
        return mMessenger;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103

接下来创建一个SensorService类。注意,因为是跨进程通信,这个服务需要对外开放。

public class SensorService extends Service {
    private static final String TAG = "SensorService";

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "bind to sensor service");
        return SensorManager.getInstance()
                .getMessenger()
                .getBinder();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在AndroidManifest添加此服务。

<service
            android:name=".SensorService"
            android:enabled="true"
            android:exported="true"></service>
  • 1
  • 2
  • 3
  • 4

最后在服务端应用的MainActivity上启动此服务。

public class MainActivity extends AppCompatActivity {

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

        Intent intent = new Intent(this,SensorService.class);
        startService(intent);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

至此,服务端的编写就完成了。下面来看看客户端的代码。

客户端代码

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    private Button mGetButton;
    private Button mOpenButton;
    private Button mShutButton;
    private TextView mTextView;

    private SensorConnection mSensorConnection;
    private ClientHandler mClientHandler;
    private Messenger mClientMessenger;
    private Messenger mSensorMessenger;

    private class ClientHandler extends Handler{
        @Override
        public void handleMessage(@NonNull Message msg) {
            Bundle bundle = msg.getData();

            //如下是服务端的相关参数
            //private static final int CMD_GET_TEMPERATURE = 0;
            //private static final int CMD_OPEN_SENSOR = 1;
            //private static final int CMD_SHUT_SENSOR = 2;
            //private static final String KEY_GET_TEMPERATURE_RESULT = "get result";
            //private static final String KEY_OPEN_SENSOR_RESULT = "open result";
            //private static final String KEY_SHUT_SENSOR_RESULT = "shut result";

            switch (msg.what){
                //private static final int CMD_GET_TEMPERATURE = 0;
                case 0:
                    double temperature = bundle.getDouble("get result");
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mTextView.setText(temperature + "℃");
                        }
                    });
                    break;

                //private static final int CMD_OPEN_SENSOR = 1;
                case 1:
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "open successfully", Toast.LENGTH_SHORT).show();
                        }
                    });
                    break;

                //private static final int CMD_SHUT_SENSOR = 2;
                case 2:
                    MainActivity.this.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            MainActivity.this.runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    Toast.makeText(MainActivity.this, "shut successfully", Toast.LENGTH_SHORT).show();
                                }
                            });
                        }
                    });
                    break;
            }
        }
    }

    private class SensorConnection implements ServiceConnection{
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mSensorMessenger = new Messenger(service);
            Log.d(TAG, "connect successfully");
        }

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

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

        mTextView = findViewById(R.id.text);
        mGetButton = findViewById(R.id.button_get);
        mOpenButton = findViewById(R.id.button_open);
        mShutButton = findViewById(R.id.button_shut);

        mGetButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Message message = Message.obtain();
                    //信封内告诉收件人谁是发送者
                    message.replyTo = mClientMessenger;
                    message.what = 0;
                    mSensorMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

        mOpenButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Message message = Message.obtain();
                    //信封内告诉收件人谁是发送者
                    message.replyTo = mClientMessenger;
                    message.what = 1;
                    mSensorMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

        mShutButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Message message = Message.obtain();
                    //信封内告诉收件人谁是发送者
                    message.replyTo = mClientMessenger;
                    message.what = 2;
                    //客户端发送数据,使用服务端的Messenger来完成
                    mSensorMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

        bindSensorService();
    }

    private void bindSensorService(){
        mSensorConnection = new SensorConnection();
        mClientHandler = new ClientHandler();
        mClientMessenger = new Messenger(mClientHandler);

		//Intent intent = new Intent("com.pyjtlk.sensorserver.SensorService"); //这是隐式绑定Service,Android5.0开始就不支持了
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.pyjtlk.sensorserver","com.pyjtlk.sensorserver.SensorService"));
        bindService(intent,mSensorConnection,BIND_AUTO_CREATE);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148

比较与思考

Messenger和AIDL都可以实现跨进程通信,那么它们的区别在哪呢?

首先,从上面的例子我们知道Messenger的数据是放在Bundle里的,而Bundle只适合少量基本类型数据的传输。相反,AIDL可以传输序列化的对象。

其次,Messenger的数据收发是异步的,而AIDL是同步的。

因为是跨进程\跨应用通信,我们并不能保证本方在发送数据时对方还活着。因此,需要引入一些机制来确定双方是否已经断开了,比如超时等待机制。

最后

服务端和客户端都放在Gitee代码仓库里了。下一篇文章我们将通过源码来分析AIDL的原理。

对Messenger源码感兴趣的朋友可以看这篇文章

参考文章

《Android Messenger使用及分析》
《android Messenger》
《关于Android Messenger的总结》

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/122635
推荐阅读
相关标签
  

闽ICP备14008679号