android学习与工作

利用Messenger跨进程通信

2019-11-05  本文已影响0人  liuye099

Android笔记多进程通信之利用Messenger跨进程通信,

    提起跨进程通信,大多数人首先会想到AIDL,AIDL,中文名称是android接口描述语言,是android系统中用于进行跨进程通信必须了解的。其实messenger和AIDL作用一样,都可以进行进程间通讯。它是基于消息的进程间通信,通过构建Message来在客户端和服务端之间传递数据,就像Handler发送消息在子线程和UI线程发送消息那样,还不用去写AIDL文件。

    Messenger翻译为信使,可以在不同进程中传递Message对象,在Message中放入我们需要传递的信息,然后通过Messenger将Message传递给对方,就可以轻轻松松实现跨进程数据传递。实际上Messenger是一种轻量级的IPC(跨进程通信)方式,它的底层仍然是实现的AIDL。

    此外,还支持记录客户端对象的Messenger,然后可以实现一对多的通信;甚至作为一个转接处,任意两个进程都能通过服务端进行通信。

Messenger与AIDL的异同

相同点:

1.都与IPC的调用有关;

2.Messenger 是一种轻量级的 IPC方案,底层实现了AIDL,只是进行了封装,开发的时候不用写.aidl文件。

3.都支持实时通信;

不同点:

1.  Messenger一次只能处理一个请求(串行)/AIDL一次可以处理多个请求(并行);

      当您需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现更加简单,因为  Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。

  对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口。

2.  Messenger不支持RPC,只能通过message传递消息/AIDL支持RPC;

3.  Messenger使用简单,轻量级,不需要创建AIDL文件/AIDL使用复杂,需要创建AIDL文件;

实现步骤:

服务端:

1.创建一个handler对象,并实现hanlemessage方法,用于接收来自客户端的消息,并作处理

2.创建一个messenger,封装handler

  private final Messenger mMessaenger = new Messenger(new MessengerHandler());

3.用messenger的getBinder()方法获取一个IBinder对象,通过onBind返回给客户端

public IBinder onBind(Intent intent){

    return mMessenger.getBinder();

}

客户端:

1.在activity中绑定服务

2.创建ServiceConnection并在其中使用 IBinder 将 Messenger实例化 

3.使用Messenger向服务端发送消息,或需要服务器端返回消息,需要创建一个messenger,封装handler,并将这个messenger传递给服务器端。在handler中接收服务器消息。这样就实现了客户端和服务端的双向通信了。

4.解绑服务

5.服务端中在 handleMessage() 方法中接收每个 Message

具体实例:

服务端:

创建一个service

public class MessengerService extends Service {

    private static final String TAG = "MessagerService";

    /**

    * 处理来自客户端的消息,并用于构建Messenger

    */

    private static class MessengerHandler extends Handler {

        @Override

        public void handleMessage(Message message) {

            switch (message.what) {

                //客户端建立连接

                case Constant.MESSAGE_FROM_CLIENT:

                    Log.e(TAG, "receive message from client:" + message.getData().getString("msg"));

                   //向客户端回传消息,

                    Message msg = Message.obtain(null, Constants.MESSAGE_FROM_SERVICE);

                    Bundle b = new Bundle();

                    b.putString("msg","hello client,I have received your connection");

                    msg.setData(b);

                    try {

                      //如果服务端需要回复客户端,则需要拿到客户端携带过来的Messenger 对象(即msg.replyTo),通过msg.replyTo.send方法给客户端发送信息

                        message.replyTo.send(msg);

                   } catch(RemoteException e){

                       e.printStackTrace();

                     }

                    break;

                case Constant.MESSAGE_FROM_API1:  //客户端测试接口1

                    Log.e(TAG, "handleMessage: receive API1: " + message.getData().getString("msg"));

                   //向客户端回传消息,

                   Message msg = Message.obtain(null, Constants.MESSAGE_TO_API1);

                   Bundle b = new Bundle();

                    b.putString("msg","hello client,I have received your API1 message!");

                   msg.setData(b);

                   try {

                     //如果服务端需要回复客户端,则需要拿到客户端携带过来的Messenger 对象(即msg.replyTo),通过msg.replyTo.send方法给客户端发送信息

                       message.replyTo.send(msg);

                   } catch(RemoteException e){

                      e.printStackTrace();

                     }

                    break;

                default:

                    super.handleMessage(message);

                    break;

            }

        }

    }

    /**

    * 构建Messenger对象

    */

    private final Messenger mMessenger = new Messenger(new MessengerHandler());

    @Nullable

    @Override

    public IBinder onBind(Intent intent) {

        //将Messenger对象的Binder返回给客户端

        return mMessenger.getBinder();

    }

}

注册service,当然要设置在不同的进程

<service

    android:name="com.example.service.MessengerService"

    android:exported="true"

    android:enabled="true"

    android:process=":remote" >

    <intent-filter>

        <action android:name="android.intent.action.SEND_MESSENGER"/>

    </intent-filter>

</service>

注意:Service在声明时必须对外开放,即android:exported="true"

客户端:

客户端是通过绑定服务端返回的binder来创建Messenger对象,并通过这个Messenger对象来向服务端发送消息。

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity ";

    private Messenger mService;

    private Button mButtonApi1, mButtonApi2;

    private TextView mTextView;

    //接收service返回的信息

    private Handler mReplyHandler = new Handler(){

        public void handleMessage(Message message){

            switch (message.what) {

                case Constant.MESSAGE_FROM_SERVICE:

                    mTextView.setText(message.getData().get("msg").toString());

                 break;

                 case Constant.MESSAGE_TO_API1:

mTextView.setText(message.getData().get("msg").toString());

                 break;

                 default:

                     super.handleMessage(message);

                  break;

            }

        }

    }

    private Messenger mClientMessenger= new Messenger(mReplyHandler);

    private ServiceConnection mConnection = new ServiceConnection() {

        @Override

        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {

            Log.e(TAG, "ServiceConnection-->" + System.currentTimeMillis());

            //通过服务端返回的Binder创建Messenger

            mService = new Messenger(iBinder);

            //创建消息,通过Bundle传递数据

            Message message = Message.obtain(null, Constants.MESSAGE_FROM_CLIENT);

            Bundle bundle = new Bundle();

            bundle.putString("msg", "hello service,this is client");

            message.setData(bundle);

           //如果需要服务器返回消息,则需要将客户端的Messenger对象传递给服务端,如果不需要返回消息,则不用加这一句。

            message.replyTo = mClientMessenger;

            try {

                //向服务端发送消息

                mService.send(message);

            } catch (RemoteException e) {

                e.printStackTrace();

            }

        }

        @Override

        public void onServiceDisconnected(ComponentName componentName) {

            Log.e(TAG, "onServiceDisconnected-->binder died");

        }

    };

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mTextView = findViewById(R.id.tv_msg);

        mButtonApi1 = findViewById(R.id.btn_send);

        //绑定服务

        Intent intent = new Intent();

        intent.setAction("android.intent.action.SEND_MESSENGER");

        intent.setPackage("com.example.service");

        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        //测试第一个接口

        mButtonApi1.setOnClickListener(new View.OnClickListener(){

             public void onClick(View v) {

                 Message message = Message.obtain(null, Constant.MESSAGE_FROM_API1);

                  Bundle bundle = new Bundle();

                  bundle.putString("msg", "hello service, this is API1 send by client");

                   message.setData(bundle);

                   //将客户端的Messenger对象传递给服务端的service

                   message.replyTo = mClientMessenger;

                   try {

                        //向服务端发送消息

                         mService.send(message);

                     } catch (RemoteException e) {

                          e.printStackTrace();

                     }

             }

         });

    }

    @Override

    protected void onDestroy() {

        //解绑服务

        unbindService(mConnection);

        super.onDestroy();

    }

}

总结

    Message中的Bundle支持多种数据类型,replyTo字段用于传输Messager对象,以便进程间相互通信

    Messager以串行的方式处理客户端发来的消息,不适合有大量并发的请求

    Messager方法只能传递消息,不能跨进程调用方法

上一篇 下一篇

猜你喜欢

热点阅读