博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IPC 之 Messenger 的使用
阅读量:4678 次
发布时间:2019-06-09

本文共 10092 字,大约阅读时间需要 33 分钟。

一、概述

  Messenger 是一种轻量级的 IPC 方案,它的底层实现是 AIDL ,对 AIDL 进行了封装,方便了对它的使用。Messenger 一次只处理一个请求,所以在服务端不用考虑线程同步的问题。下面给出一张 Messenger 的工作原理图来了解一下其工作原理:

  根据上面原理图,要通过 Messenger 进行进程间通信,在 Cilent 和 Server 端扮演重要角色的有 Handler 、Message 、Messenger 。Message  和 Messenger 是实现 Parcelable 接口的,所以可以在进程间进行传递。Message 是我们所要传递信息的载体,Messenger 提供了 传递的渠道,而 Handler 是 最终的信息接受和处理中心。当然本身 Handler  是无法进行接受消息的,还是由在创建 Messenger 时,Messenger 持有了 Handler 的对象 ,在 Messenger 内部调用了 Handler 的 handleMessage 方法,让其去处理 Message 。下面我们就开始通过代码来实现:

二、编码实现

  示例主要由 客户端  和 服务端 两个独立 App 进行 IPC ,传输的类型为自定义类型,所以它一定实现了 Parcelable 接口。

  1. 服务端

    服务端工程目录:

    

    根据目录,来看 User :

package com.sl.messengerclient;import android.os.Parcel;import android.os.Parcelable;public class User implements Parcelable {    private String name;    private int age;    public User(String name, int age) {        this.name = name;        this.age = age;    }    protected User(Parcel in) {        name = in.readString();        age = in.readInt();    }    public static final Creator
CREATOR = new Creator
() { @Override public User createFromParcel(Parcel in) { return new User(in); } @Override public User[] newArray(int size) { return new User[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); } @Override public String toString() { return "[ name = " + name + " , age = " + age + "]"; }}

    服务MessengerService 的编码实现:

package com.sl.messengerserver;import android.app.Service;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import com.sl.messengerclient.User;import java.lang.ref.WeakReference;import java.util.ArrayList;public class MessengerService extends Service {    private static final String USER_LIST = "user_list";    private static final int ADD_USER_REQUEST = 0x001;    private static final int USER_LIST_REQUEST = 0x0002;    private static final String ADD_USER = "add_user";    public ArrayList
mUserList; private static class MessengerHandler extends Handler { WeakReference
wrService; MessengerHandler(MessengerService messengerService) { wrService = new WeakReference<>(messengerService); } @Override public void handleMessage(Message msg) { switch (msg.what) { case ADD_USER_REQUEST: Bundle bundle = msg.getData(); bundle.setClassLoader(Thread.currentThread().getContextClassLoader()); User user = bundle.getParcelable(ADD_USER); wrService.get().mUserList.add(user); Message message = Message.obtain(null, ADD_USER_REQUEST); try { msg.replyTo.send(message); } catch (RemoteException e) { e.printStackTrace(); } break; case USER_LIST_REQUEST: Message userMsg = Message.obtain(null, USER_LIST_REQUEST); Bundle data = new Bundle(); data.putParcelableArrayList(USER_LIST, wrService.get().mUserList); userMsg.setData(data); try { msg.replyTo.send(userMsg); } catch (RemoteException e) { e.printStackTrace(); } break; default: super.handleMessage(msg); } } } private Messenger mMessenger = new Messenger(new MessengerHandler(this)); @Override public IBinder onBind(Intent intent) { return mMessenger.getBinder(); } @Override public void onCreate() { super.onCreate(); mUserList = new ArrayList<>(); }}

    服务端这里有一点需要特别注意,使用 Messenger 传递自定义对象的时候,在接收端(不论是服务端或者客户端)拿到传递过来的自定义对象,示例里的 User 。都需要在获取之前添加代码中标红的那句代码:

bundle.setClassLoader(Thread.currentThread().getContextClassLoader());

    不添加这句的后果就是会出现 ClassNotFoundException ,为什么会出现这样的错误?Bundle 里本身存储了一个 类加载器,这个类加载器是发送方的,但是类加载器本身没有实现 Parcelable 接口 ,所以传递不过来。这里设置当前为当前类加载器,就能找到我们自定义的对象类。

       服务端记得在 AndroidManifest.xml 中申明 ,在 Activity 中启动,服务端就这样了。

  2. 客户端

    客户端工程目录:

    

    服务端的 User 是从 这里的 User 拷贝过去的,所以看上面的就可以了。直接看 MessengerClientActivity :

package com.sl.messengerclient;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;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.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.widget.EditText;import android.widget.LinearLayout;import android.widget.TextView;import android.widget.Toast;import java.lang.ref.WeakReference;import java.util.ArrayList;public class MessengerClientActivity extends AppCompatActivity {    private static final String PACKAGE_REMOTE_SERVICE = "com.sl.messengerserver";    private static final String NAME_REMOTE_SERVICE = "com.sl.messengerserver.MessengerService";    private static final String USER_LIST = "user_list";    private static final int ADD_USER_REQUEST = 0x001;    private static final int USER_LIST_REQUEST = 0x0002;    private static final String ADD_USER = "add_user";    private Messenger mService;    public LinearLayout bookContainer;    private Messenger mGetRelyMessenger = new Messenger(new MessengerHandler(this));    private ServiceConnection mConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mService = new Messenger(service);        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        bookContainer = findViewById(R.id.container);        Intent intent = new Intent();        ComponentName componentName = new ComponentName(PACKAGE_REMOTE_SERVICE, NAME_REMOTE_SERVICE);        intent.setComponent(componentName);        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);    }    public void sendAddUserMsg(View view) {        if (mService == null) {            Toast.makeText(this, "服务器未连接", Toast.LENGTH_LONG).show();            return;        }        Message message = Message.obtain(null, ADD_USER_REQUEST);        Bundle data = new Bundle();        EditText etUserName = findViewById(R.id.user_name);        EditText etUserAge = findViewById(R.id.user_age);        data.putParcelable(ADD_USER, new User(etUserName.getText().toString(), Integer.valueOf(etUserAge.getText().toString())));        message.setData(data);        message.replyTo = mGetRelyMessenger;        try {            mService.send(message);        } catch (RemoteException e) {            e.printStackTrace();        }    }    public void sendGetUserListMsg(View view) {        if (mService == null) {            Toast.makeText(this, "服务器未连接", Toast.LENGTH_LONG).show();            return;        }        Message message = Message.obtain(null, USER_LIST_REQUEST);        message.replyTo = mGetRelyMessenger;        try {            mService.send(message);        } catch (RemoteException e) {            e.printStackTrace();        }    }    @Override    protected void onDestroy() {        super.onDestroy();        unbindService(mConnection);    }    private static class MessengerHandler extends Handler {        WeakReference
wrContext; MessengerHandler(MessengerClientActivity mainActivity) { wrContext = new WeakReference<>(mainActivity); } @Override public void handleMessage(Message msg) { switch (msg.what) { case USER_LIST_REQUEST: Bundle bundle = msg.getData(); bundle.setClassLoader(Thread.currentThread().getContextClassLoader()); ArrayList
users = bundle.getParcelableArrayList(USER_LIST); showBooks(users, wrContext); break; case ADD_USER_REQUEST: Toast.makeText(wrContext.get().getApplicationContext(), "添加用户成功", Toast.LENGTH_SHORT).show(); break; default: super.handleMessage(msg); } } private void showBooks(ArrayList
users, WeakReference
wrContext) { wrContext.get().bookContainer.removeAllViews(); if (users != null && users.size() > 0) { for (User user : users) { LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); TextView textView = new TextView(wrContext.get()); params.gravity = Gravity.CENTER_HORIZONTAL; textView.setGravity(Gravity.CENTER); params.topMargin = 10; textView.setLayoutParams(params); textView.requestLayout(); textView.setText(user.toString()); wrContext.get().bookContainer.addView(textView); } } } }}

  看一下布局文件:

  3. 运行效果:

    启动服务端,然后运行客户端查看结果:

 

三、总结

  Messenger 使用起来确实比 AIDL 方便的多,不需要创建 AIDL 文件。但是它是对 AIDL 的封装,是一个轻量型的 IPC 方案,所以 AIDL 需要注意的它也需要注意。我们后续会对比每种IPC方案,来让我们选择合适的方案。AIDL 的具体使用,具体可以查看这篇: 。

  

 

转载于:https://www.cnblogs.com/aimqqroad-13/p/8964072.html

你可能感兴趣的文章
bzoj1511 [POI2006]OKR-Periods of Words kmp+乱搞
查看>>
心语4
查看>>
Telink MESH SDK 如何使用PWM
查看>>
LR SP PC
查看>>
C# 图片识别(支持21种语言)【转】
查看>>
C# 循环语句 for
查看>>
jQuery基础教程
查看>>
python class(1)
查看>>
模拟手工测试操作页面上的元素---留
查看>>
P2709 小B的询问
查看>>
九度OJ 1054:字符串内排序 (排序)
查看>>
第三组的抓包作业
查看>>
ILNumerics项目的应用之线性方程
查看>>
django考点
查看>>
python-socket
查看>>
.NET 分布式技术比较
查看>>
SpringMVC视频
查看>>
Android中intent如何传递自定义数据类型
查看>>
Android蓝牙音乐获取歌曲信息
查看>>
android基础---->子线程更新UI
查看>>