❤️ Android IPC 之 Messenger使用 ❤️

简介: 🔥 绑定服务(Bound Services)概述 绑定服务是client-server接口中的服务器。它允许组件(例如活动)绑定到服务、发送请求、接收响应和执行进程间通信(IPC)。 绑定服务通常仅在它为另一个应用程序组件提供服务时才存在,并且不会无限期地在后台运行。

 上文讲到了进程间通信(IPC)原理,这里咱们来一起学习一下具体实现。


🔥 绑定服务(Bound Services)概述


       绑定服务是client-server接口中的服务器。它允许组件(例如活动)绑定到服务、发送请求、接收响应和执行进程间通信(IPC)。 绑定服务通常仅在它为另一个应用程序组件提供服务时才存在,并且不会无限期地在后台运行。


💥 基础知识


       绑定服务是 Service 类的实现,它允许其他应用程序绑定到它并与之交互。 要为服务提供绑定,你必须实现 onBind() 回调方法。 此方法返回一个 IBinder 对象,该对象定义了客户端可用于与服务交互的编程接口。


🔥 Messenger


💥 概述


       一提到IPC 很多人的反应都是 AIDL,其实如果仅仅是多进程单线程,那么你可以使用 Messenger 为你的服务提供接口。


       使用 Messenger 比使用 AIDL 更简单,因为 Messenger 会将所有对服务的调用排入队列。


       对于大多数应用程序,该服务不需要执行 多线程 ,因此使用 Messenger 允许该服务一次处理一个调用。如果你的 服务多线程很重要,那你就要用到ALDL了。


💥 使用 Messenger 步骤


  • 1、该 Service 实现了一个 Handler,该 Handler 接收来自客户端的每次调用的回调。


  • 2、该服务使用 Handler 创建一个 Messenger 对象(它是对 Handler 的引用)。


  • 3、Messenger 创建一个 IBinder,该服务从 onBind() 返回给客户端。


  • 4、客户端使用 IBinder 来实例化 Messenger(引用服务的Handler),客户端使用 Handler 来向服务发送 Message 对象。


  • 5、服务在其 Handler 的 handleMessage() 中接收每个消息。


💥 实例(Client到Server数据传递)


🌀 MessengerService.java


public class MessengerService extends Service {
    public static final int MSG_SAY_HELLO = 0;
    //让客户端向IncomingHandler发送消息。
    Messenger messenger = null;
    //当绑定到服务时,我们向我们的Messenger返回一个接口,用于向服务发送消息。
    public IBinder onBind(Intent intent) {
        MLog.e("MessengerService:onBind");
        //创建 Messenger 对象(对 Handler 的引用)
        messenger = new Messenger(new IncomingHander(this));
        //返回支持此Messenger的IBinder。
        return messenger.getBinder();
    }
    //实现了一个 Handler
    static class  IncomingHander extends Handler {
        private Context appliacationContext;
        public IncomingHander(Context context) {
            appliacationContext = context.getApplicationContext();
        }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_SAY_HELLO:
                    Bundle bundle = msg.getData();
                    String string = bundle.getString("name");
                    //处理来自客户端的消息
                    MLog.e("handleMessage:来自Acitvity的"+string);
                    break;
                case 1:
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
}


🌀 AndroidMainfest.xml


        <service android:name=".ipc.MessengerService"
            android:process="com.scc.ipc.messengerservice"
            android:exported="true"
            android:enabled="true"/>


使用 android:process 属性 创建不同进程。


🌀 MainActivity.class


1.public class MainActivity extends ActivityBase implements View.OnClickListener {
    Messenger mService = null;
    Messenger messenger = null;
    private boolean bound;
    private ViewStub v_stud;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
    }
    ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //从原始 IBinder 创建一个 Messenger,该 IBinder 之前已使用 getBinder 检索到。
            mService = new Messenger(service);
            bound = true;
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            bound = false;
        }
    };
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_bind_service:
                bindService(new Intent(MainActivity.this, MessengerService.class), connection, Context.BIND_AUTO_CREATE);
                break;
            case R.id.btn_send_msg:
                Message message = Message.obtain(null, MessengerService.MSG_SAY_HELLO);
                Bundle bundle = new Bundle();
                bundle.putString("name","Scc");
                message.setData(bundle);
                try {
                    mService.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }
    @Override
    protected void onStop() {
        super.onStop();
        if (bound) {
            unbindService(connection);
            bound = false;
        }
    }
}


🌀 运行效果如下


微信图片_20220524112504.png


两个进程也存在着,也完成了进程间的通信,并把数据传递过去了。


💥 实例(Server将数据传回Client)


       我不仅想将消息传递给 Server ,还想让 Server 将数据处理后传会Client。


🌀 MessengerService.java


public class MessengerService extends Service {
    /** 用于显示和隐藏我们的通知。 */
    ArrayList<Messenger> mClients = new ArrayList<Messenger>();
    /** 保存客户端设置的最后一个值。 */
    int mValue = 0;
    /**
     * 数组中添加 Messenger (来自客户端)。
     * Message 的 replyTo 字段必须是应该发送回调的客户端的 Messenger。
     */
    public static final int MSG_REGISTER_CLIENT = 1;
    /**
     * 数组中删除 Messenger (来自客户端)。
     * Message 的 replyTo 字段必须是之前用 MSG_REGISTER_CLIENT 给出的客户端的 Messenger。
     */
    public static final int MSG_UNREGISTER_CLIENT = 2;
    /**
     * 用于设置新值。
     * 这可以发送到服务以提供新值,并将由服务发送给具有新值的任何注册客户端。
     */
    public static final int MSG_SET_VALUE = 3;
    //让客户端向IncomingHandler发送消息。
    Messenger messenger = null;
    //当绑定到服务时,我们向我们的Messenger返回一个接口,用于向服务发送消息。
    public IBinder onBind(Intent intent) {
        MLog.e("MessengerService-onBind");
        //创建 Messenger 对象(对 Handler 的引用)
        messenger = new Messenger(new IncomingHander(this));
        //返回支持此Messenger的IBinder。
        return messenger.getBinder();
    }
    //实现了一个 Handler
    class  IncomingHander extends Handler {
        private Context appliacationContext;
        public IncomingHander(Context context) {
            appliacationContext = context.getApplicationContext();
        }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_REGISTER_CLIENT:
                    mClients.add(msg.replyTo);
                    break;
                case MSG_UNREGISTER_CLIENT:
                    mClients.remove(msg.replyTo);
                    break;
                case MSG_SET_VALUE:
                    mValue = msg.arg1;
                    for (int i=mClients.size()-1; i>=0; i--) {
                        try {
                            mClients.get(i).send(Message.obtain(null,
                                    MSG_SET_VALUE, mValue, 0));
                        } catch (RemoteException e) {
                            // 客户端没了。 从列表中删除它;
                            //从后往前安全,从前往后遍历数组越界。
                            mClients.remove(i);
                        }
                    }
                default:
                    super.handleMessage(msg);
            }
        }
    }
}


🌀 MainActivity.java


public class MainActivity extends ActivityBase implements View.OnClickListener {
    Messenger mService = null;
    Messenger messenger = null;
    private boolean bound;
    private ViewStub v_stud;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
    }
    ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //从原始 IBinder 创建一个 Messenger,该 IBinder 之前已使用 getBinder 检索到。
            mService = new Messenger(service);
            bound = true;
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            bound = false;
        }
    };
    static class ReturnHander extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MessengerService.MSG_SET_VALUE:
                    //我要起飞:此处处理
                    MLog.e("Received from service: " + msg.arg1);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_bind_service:
                bindService(new Intent(MainActivity.this, MessengerService.class), connection, Context.BIND_AUTO_CREATE);
                break;
            case R.id.btn_send_msg:
                try {
                    mMessenger = new Messenger(new ReturnHander());
                    Message msg = Message.obtain(null,
                            MessengerService.MSG_REGISTER_CLIENT);
                    msg.replyTo = mMessenger;
                    //先发一则消息添加Messenger:msg.replyTo = mMessenger;
                    mService.send(msg);
                    // Give it some value as an example.
                    msg = Message.obtain(null,
                            MessengerService.MSG_SET_VALUE, this.hashCode(), 0);
                    //传入的arg1值:this.hashCode()
                    mService.send(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
        }
    }
    @Override
    protected void onStop() {
        super.onStop();
        if (bound) {
            unbindService(connection);
            bound = false;
        }
    }
}


🌀 运行效果如下


微信图片_20220524112620.png


我们在MainActivity 的 Handler.sendMessger()中接收到了来自 MesengerService 的消息 。


       本次 Messenger 进程间通信齐活,这只是个简单的Demo。最后咱们看一波源码。


🔥 Messenger 源码


💥 Messenger.java


public final class Messenger implements Parcelable {
    private final IMessenger mTarget;
    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }
    public IBinder getBinder() {
        return mTarget.asBinder();
    }
    ...
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }
}


然后你会发现 只要代码还是在 IMessenger 里面,咱们去找找。


💥 IMessenger.aidl


package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
    void send(in Message msg);
}


💥 new Messenger(Handler handelr)


       这里其实是用Handler 调用 getIMessenger() 。咱们去Handler.class里面转转。


    @UnsupportedAppUsage
    final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }
    //创建了Messenger实现类
    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            //Messenger调用send()方法,通过Handler发送消息。
            //然后在服务端通过Handler的handleMessge(msg)接收这个消息。
            Handler.this.sendMessage(msg);
        }
    }


💥 new Messenger(IBinder target)


package android.os;
/** @hide */
public interface IMessenger extends android.os.IInterface
{
  /** Default implementation for IMessenger. */
  public static class Default implements android.os.IMessenger
  {
    @Override public void send(android.os.Message msg) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements android.os.IMessenger
  {
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an android.os.IMessenger interface,
     * generating a proxy if needed.
     */
    public static android.os.IMessenger asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      //判断是否在同一进程。
      if (((iin!=null)&&(iin instanceof android.os.IMessenger))) {
        //同一进程
        return ((android.os.IMessenger)iin);
      }
      //代理对象
      return new android.os.IMessenger.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    ...
  }
  public void send(android.os.Message msg) throws android.os.RemoteException;
}


看了上面代码你会发现这不就是个aidl吗? 什么是aidl,咱们下一篇继续讲到。



相关文章
|
8月前
|
编解码 前端开发 Android开发
如何让Android平台像IPC一样实现GB28181前端设备接入
好多开发者在做国标对接的时候,首先想到的是IPC摄像头,通过参数化配置,接入到国标平台,实现媒体数据的按需查看等操作。
|
8月前
|
编解码 开发工具 Android开发
如何在Android端实现轻量级RTSP服务(类似于IPC)
首先声明一点,本blog提到的轻量级RTSP服务,类似于网络摄像头(IPC),而非传统意义的接受外部推流的RTSP服务器。
467 0
|
Java Android开发
Android IPC系列(一):AIDL使用详解
AIDL可以实现进程间的通信,由于每个进程都是运行在独立的空间,不同的进程想要交互需要借助一些特殊的方式,AIDL就是其中的一种,AIDL是一种模板,因为实际交互过程中,并不是AIDL起的作用,具体会在之后源码分析解释,AIDL的作用是为了避免重复编写代码而出现的一个模板
|
Android开发
Android IPC 之 AIDL 原理
Android IPC 之 AIDL 原理
Android IPC 之 AIDL 原理
|
存储 API Android开发
深入剖析Android四大组件(四)——Messenger实现Android IPC
深入剖析Android四大组件(四)——Messenger实现Android IPC
114 2
|
编解码 Java 编译器
深入剖析Android四大组件(三)——AIDL实现Android IPC
深入剖析Android四大组件(三)——AIDL实现Android IPC
126 0
深入剖析Android四大组件(三)——AIDL实现Android IPC
|
Java Linux API
Framework笔记 | Android Framework用到了哪些IPC方式,分别在哪里用到
Framework笔记 | Android Framework用到了哪些IPC方式,分别在哪里用到
|
监控 Java Android开发
Android | IPC进程间通信 之 AIDL实践
Android | IPC进程间通信 之 AIDL实践
|
Java 开发工具 Android开发
Android IPC 之 AIDL 使用
🔥 AIDL AIDL 全称 Android Interface Definition Language (Android 接口定义语言),允许你定义客户端和服务都同意的编程接口,以便使用进程间通信 (IPC) 相互通信。在Android上,一个进程不能正常访问另一个进程的内存,因此 Android 使用 AIDL 为你处理。
228 0
Android IPC 之 AIDL 使用
|
JSON Java API
XIPC 一个Android通用的IPC(进程通信)框架。
XIPC 一个Android通用的IPC(进程通信)框架。
590 0
XIPC 一个Android通用的IPC(进程通信)框架。