• 【Android


    参考资料:

    1、《Android开发艺术探索》第二章2.4.3

    2、【Messenger完全解析】

    1、Messenger概述

      Messenger,译为“信使”,是Android中一种基于Binder机制的IPC(Inter-Process Communication,进程间通信)方式。通过Messenger可以在不同进程中传递Message对象,在Message中放入我们需要传递的数据,就可以轻松的实现进程间数据的传递了。即:Messenger允许实现基于消息的进程间通信的方式。

      Messenger是一种轻量级的IPC方案,其实现底层是AIDL。

      Messenger一次只能处理一个请求,因此在服务端我们不用考虑线程同步的问题,这是因为服务端不存在并发执行的情形。

      使用Messenger进行进程间通信的具体流程是:客户端发送一个Message给服务端,在服务端的Handler中接收到客户端的消息,然后进行对应的处理,处理完成后再将结果等数据封装成Message对象,发送给客户端,客户端的Handler中会接收到服务端传过来的数据并进行处理。

    2、Messenger通信实例

      在这个例子中,客户端的界面上有一个按钮,通过点击这个按钮,向服务端发送两个参数,服务端将这两个参数相加后回传给客户端,客户端收到答案之后显示到界面上。

    2.1、服务端

      服务端的需要新建一个Service,命名为MessengerService,代码如下:

    package my.itgungnir.server;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.Messenger;
    import android.support.annotation.Nullable;
    
    /**
     * Messenger 服务端Service
     * Created by ITGungnir on 2017/4/5.
     */
    public class MessengerServer extends Service {
        private static final int MSG_GETSUM = 0x001;
    
        // Messenger对象,其中的Handler用来接收从客户端传过来的Message,通过可以创建Message对象回传给客户端
        Messenger mMessenger = new Messenger(new Handler() {
            @Override
            public void handleMessage(Message msgFromClient) {
                // 要回传给客户端的Message对象
                Message msgToClient = Message.obtain(msgFromClient);
                switch (msgFromClient.what) {
                    case MSG_GETSUM:
                        msgToClient.what = MSG_GETSUM;
                        try {
                            Thread.sleep(2000); // 模拟耗时
                            msgToClient.arg2 = msgFromClient.arg1 + msgFromClient.arg2;
                            // Message的replyTo也是一个Messenger对象
                            msgFromClient.replyTo.send(msgToClient);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                }
                super.handleMessage(msgFromClient);
            }
        });
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return mMessenger.getBinder(); // 获取Messenger中的IBinder对象
        }
    }

      可以看到,服务端要做的工作是手动创建一个Messenger,然后在onBind()方法中返回这个Messenger对象的getBinder()对象。

      在创建的Messenger中,参数是一个Handler,即从客户端向服务端发送消息时,就是将消息发送到了这个Handler对象中。因此,我们需要在这个Handler对象中处理客户端传过来的消息,当然也可以创建一个新的消息,返回给客户端。

      因为服务端使用了Android四大组件中的Service,因此需要在Menifest文件中进行注册,代码如下:

    <service android:name=".MessengerServer">
        <intent-filter>
            <action android:name="my.itgungnir.messenger.getsum" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </service>

    2.2、客户端

      在客户端中需要做的事情比服务端多。首先,我们需要先绑定到服务端的服务上,然后才可以向服务端请求服务。下面是客户端首页MainActivity.java类中的代码:

    package my.itgungnir.client;
    
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    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.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private static final int MSG_GETSUM = 0x001;
    
        private LinearLayout container; // 盛放所有算术题的TextView的容器(LinearLayout)
        private TextView state; // 显示服务器连接状态的TextView
        private Button require; // 向服务端请求算术题答案的按钮
    
        private Messenger mService; // 客户端的Messenger对象
        private boolean isConnected; // 指示是否连接到服务端
        private int mArg1 = 0; // 算术题的被加数,同时也是TextView的id
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initViews();
            bindToServer();
        }
    
        // 初始化界面中的布局,并绑定相应的事件
        private void initViews() {
            container = (LinearLayout) findViewById(R.id.client_ly_container);
            state = (TextView) findViewById(R.id.client_tv_connection);
            require = (Button) findViewById(R.id.client_btn_require);
            require.setOnClickListener(this);
        }
    
        // 获取服务端绑定状态的ServiceConnection对象
        private ServiceConnection connection = new ServiceConnection() {
            @Override // 绑定服务端成功时回调的方法
            public void onServiceConnected(ComponentName name, IBinder service) {
                mService = new Messenger(service);
                isConnected = true;
                state.setText("Server Connected!");
            }
    
            @Override // 绑定服务端失败时回调的方法
            public void onServiceDisconnected(ComponentName name) {
                mService = null;
                isConnected = false;
                state.setText("Server Not Connected!");
            }
        };
    
        // 绑定到服务端
        private void bindToServer() {
            Intent intent = new Intent();
            intent.setAction("my.itgungnir.messenger.getsum");
            // Android 5.0 及以上的设备需要为intent设置package,否则会报错:Service Intent must be explicit
            intent.setPackage("my.itgungnir.server");
            bindService(intent, connection, Context.BIND_AUTO_CREATE);
        }
    
        // 客户端的Messenger对象
        private Messenger mMessenger = new Messenger(new Handler() {
            @Override
            public void handleMessage(Message msgToClient) {
                switch (msgToClient.what) {
                    case MSG_GETSUM:
                        // 接收服务端回传的数据并在Handler中更新UI
                        TextView tv = (TextView) findViewById(msgToClient.arg1);
                        tv.setText(tv.getText() + " ==> " + msgToClient.arg2);
                        break;
                }
                super.handleMessage(msgToClient);
            }
        });
    
        // 每点击一次按钮,就向服务端发送一条消息
        @Override
        public void onClick(View v) {
            try {
                int arg1 = ++mArg1;
                int arg2 = (int) (Math.random() * 90 + 10);
                TextView tv = new TextView(MainActivity.this);
                tv.setTextSize(18f);
                tv.setText(arg1 + " + " + arg2 + " = Calculating... ");
                tv.setId(arg1);
                container.addView(tv);
                // 要发送到服务端的Message对象
                Message msgFromClient = Message.obtain(null, MSG_GETSUM, arg1, arg2);
                msgFromClient.replyTo = mMessenger;
                if (isConnected) {
                    // 将消息发送给服务端Messenger的Handler对象
                    mService.send(msgFromClient);
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(connection);
        }
    }

      从代码中可以看到,调用bindService()方法之后,在ServiceConnection对象的回调方法中的onServiceConnected()方法(连接服务端成功的回调方法)中,会携带一个IBinder类型的参数,这个参数就是服务端的服务对象,我们可以通过 new Messenger(service) 方法获取到服务端的Messenger对象,然后就可以通过这个Messenger对象,向服务端的Handler发送消息了。

      布局文件activity_main.xml文件中的代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/client_ly_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="15.0dip">
    
        <TextView
            android:id="@+id/client_tv_connection"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@android:color/black"
            android:textSize="20.0sp"
            android:textStyle="bold" />
    
        <Button
            android:id="@+id/client_btn_require"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="15.0dip"
            android:layout_marginTop="15.0dip"
            android:text="Send Message To Server" />
    
    </LinearLayout>

    2.3、运行结果

      先运行服务端,再运行客户端,如果连接服务端成功,客户端的状态TextView中会显示 connected 字样;此时我们点击客户端中的按钮,向服务端发送算术题,然后等待服务端计算后将结果返回给客户端。

      运行结果如下图所示:

     

    3、 总结

      从上面的例子中,我们大致可以看出Messenger的工作机制:

      主要是客户端向服务端发送消息请求服务,服务端接收到客户端的请求后提供相应的服务,然后将服务结果封装成消息对象回传给客户端,客户端收到服务端的回传结果对其进行处理使用(如更新UI界面)。

      这里需要注意的有三点:

    • Messenger中的send()方法:这个方法的作用是将一个Message对象发送给调用这个方法的Messenger的Handler对象(就是new Messenger的时候参数中传入的Handler对象);
    • Message对象有一个Messenger类型的replyTo属性,这个属性指定了这条消息的回传对象。在上面的例子中,我们在客户端指定了发送给服务端的Message的replyTo属性是客户端的Messenger,这样在服务端才更容易的拿到客户端的具体的Messenger对象并进行消息的回传;
    • Messenger的底层实现是AIDL,其机制也和AIDL相同。
  • 相关阅读:
    51nod1229 序列求和 V2
    51nod 1228、1258 序列求和
    题解P3711:【仓鼠的数学题】
    伯努利数学习笔记的说...
    题解 P4692 【[Ynoi2016]谁的梦】
    积性函数与卷积
    题解 P5065 【[Ynoi2014]不归之人与望眼欲穿的人们】
    [Ynoi2018]末日时在做什么?有没有空?可以来拯救吗?
    [51nod1965]奇怪的式子
    PGCD2
  • 原文地址:https://www.cnblogs.com/itgungnir/p/6668671.html
Copyright © 2020-2023  润新知