Android使用Messenger跨进程通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxlworking1/article/details/80359448

1.了解Messenger

最近在看系统APP时,看到系统在跨进程通信中没有使用AIDL,直接使用了Messenger来处理,之前没有遇到过,故特地研究了一下,并在此记录。
##1.1Messenger概念
来看下API文档中关于Messenger的介绍:


If you need your interface to work across different processes, you can create an interface for the service with a Messenger. In this manner, the service defines a Handler that responds to different types of Message objects. This Handler is the basis for a Messenger that can then share an IBinder with the client, allowing the client to send commands to the service using Message objects. Additionally, the client can define a Messenger of its own so the service can send messages back.
This is the simplest way to perform interprocess communication (IPC), because the Messenger queues all requests into a single thread so that you don’t have to design your service to be thread-safe.


其意思为:
如果你需要你的接口能够跨进程工作,你可以创建一个带Messenger的Service。
以这种方式,其创建的Service定义了一个Handler可以响应不同类型的消息体
这个Handler是Messenger的基础,其可以通过IBinder机制,使客户端可以发送命令、消息体到服务端
此外,客户端也可以定义一个Messenger给服务端,使服务端可以发送消息给客户端
这个是一个最简单的跨进程通信方法,因为Messenger将所有的请求放入一个消息队列中,并在一个单独的线程中管理,这样你就不用担心线程安全的问题了。

1.2Messenger与AIDL区别

从上面关于Messenger的解释,我们可以看出其与AIDL的区别:


  1. Messenger是以Handler为基础的,其封装了AIDL与Handler,使客户端与服务端交互看起来像是Handler、Message;而AIDL是跨进程调用对方提供的接口 。
  2. 由于一个Service对应一个Messenger,并对应一个Handler,所以其服务端在一个独立线程中处理消息队列中的消息请求,这个样多个客户端请求,其对应的同一个服务端要排队依次处理请求消息;而AIDL对应的Service,每接收到一个请求,则会新建一个线程单独处理,即不用排队等待处理消息。
  3. 由于Messenger是以Handler的机制处理消息,所以每次请求都是异步处理,不能立刻获得结果,需要服务端通过客户端的Messenger通知客户端;而AIDL默认调用接口是同步处理,也可以在服务端接口处理中以异步的方式处理,从而达到异步效果。
    #2.使用注意点
    ##2.1Service启动不了
    1.需要在AndroidManifest.xml注册Service
    2.添加Service属性exported=“true”
<service android:name=".TestService"
	android:exported="true"/>

2.2跨进程传递Object不能识别

会出现如下异常错误**“android.os.BadParcelableException: ClassNotFoundException when unmarshalling”**
该问题是由于APK对应的ClassLoader不再使用时被系统回收了,当再次调用加载APK下的类时,不能加载成功导致


其解决方法是再次设置ClassLoadere
在收到Messenger发送的消息后,通过Message获取其中的Bundle,然后设置ClassLoader
Bundle.setClassLoader(getClass().getClassLoader());

E/Parcel: Class not found when unmarshalling: test.zxl.com.test_messenger.data.TestObject
java.lang.ClassNotFoundException: test.zxl.com.test_messenger.data.TestObject
	...
Caused by: java.lang.ClassNotFoundException: Didn't find class "test.zxl.com.test_messenger.data.TestObject" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib, /system/vendor/vehicle/lib]]
	... 18 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

D/AndroidRuntime: Shutting down VM

--------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
Process: test.zxl.com.test_messenger_server, PID: 14563
android.os.BadParcelableException: ClassNotFoundException when unmarshalling: test.zxl.com.test_messenger.data.TestObject
	at android.os.Parcel.readParcelableCreator(Parcel.java:2295)
	at android.os.Parcel.readParcelable(Parcel.java:2245)
	at android.os.Parcel.readValue(Parcel.java:2152)
	at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)
	at android.os.BaseBundle.unparcel(BaseBundle.java:221)
	at android.os.BaseBundle.get(BaseBundle.java:280)
	at test.zxl.com.test_messenger_server.TestService$1.handleMessage(TestService.java:56)
	at android.os.Handler.dispatchMessage(Handler.java:102)
	at android.os.Looper.loop(Looper.java:135)
	at android.app.ActivityThread.main(ActivityThread.java:5309)
	at java.lang.reflect.Method.invoke(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:372)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1249)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1044)

2.3跨进程嵌套Object,序列化不完全

当在跨进程发送消息时,其消息是一个对象,并且对象中还有对象,如果序列化不完全,则获取的值会为null


序列化方法:
子对象实现Parcelable接口
父对象在读取时,要将子对象读取出来;父对象在写入序列化时,将子对象也要写入;

    protected TestObject(Parcel in) {
        testInt = in.readInt();
        testStr = in.readString();
        mTestChildObject = in.readParcelable(TestChildObject.class.getClassLoader());
    }
    
	@Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(testInt);
        dest.writeString(testStr);
        dest.writeParcelable(mTestChildObject,flags);
    }

3.编写Demo

3.1编写Service

package test.zxl.com.test_messenger_server;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
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 android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;

import test.zxl.com.test_messenger.data.TestChildObject;
import test.zxl.com.test_messenger.data.TestObject;

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

    private static final String ACTION_STOP_SERVICE = "ACTION_STOP_SERVICE";

    private static final int MSG_TEST_BASIC = 1;
    private static final int MSG_TEST_OBJECT = 2;

    private Messenger mMessenger = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_TEST_BASIC:
                    Bundle mBundleBasic = msg.getData();
                    mBundleBasic.setClassLoader(getClass().getClassLoader());
                    Log.d(TAG,"server::MSG_TEST_BASIC::msg.arg1 = " + msg.arg1 + "::msg.objct = " + mBundleBasic.get("MSG_TEST_BASIC"));

                    Message messageBasic = Message.obtain();
                    messageBasic.what = MSG_TEST_BASIC;
                    mBundleBasic = new Bundle();
                    mBundleBasic.putInt("MSG_TEST_BASIC",112233);
                    messageBasic.setData(mBundleBasic);
                    try {
                        msg.replyTo.send(messageBasic);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }

                    break;
                case MSG_TEST_OBJECT:
                    Bundle mBundleObject = msg.getData();
                    mBundleObject.setClassLoader(getClass().getClassLoader());
                    Object mObjectData = mBundleObject.get("MSG_TEST_OBJECT");
                    TestObject mTestObject = null;
                    if(mObjectData instanceof TestObject){
                        mTestObject = (TestObject)mObjectData;
                    }
                    Log.d(TAG,"server::MSG_TEST_OBJECT::msg.objct = " + mTestObject);

                    Message messageObject = Message.obtain();
                    messageObject.what = MSG_TEST_OBJECT;
                    TestChildObject mTestChildObject = new TestChildObject();
                    mTestObject.mTestChildObject = mTestChildObject;
                    mTestObject.testInt = 112255;
                    mTestObject.testStr="server";
                    mTestObject.mTestChildObject.testInt = 112266;
                    mTestObject.mTestChildObject.testStr = "server_child";
                    mBundleObject.putParcelable("MSG_TEST_OBJECT",mTestObject);
                    messageObject.setData(mBundleObject);
                    try {
                        msg.replyTo.send(messageObject);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
            }
        }
    });

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG,"onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG,"onBind");
        return mMessenger.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG,"onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Log.d(TAG,"onDestroy");
        super.onDestroy();
    }

    class StopReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String mAction = intent.getAction();
            Log.d(TAG,"onReceive::mAction = " + mAction);
            if(TextUtils.equals(mAction,ACTION_STOP_SERVICE)){
                stopSelf();
            }
        }
    }
}

3.2AndroidManifest注册Service

	<service android:name=".TestService"
		android:exported="true"/>

3.3编写客户端

package test.zxl.com.test_messenger_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.util.Log;
import android.view.View;
import android.widget.Button;

import test.zxl.com.test_messenger.data.TestChildObject;
import test.zxl.com.test_messenger.data.TestObject;

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

    private static final int MSG_TEST_BASIC = 1;
    private static final int MSG_TEST_OBJECT = 2;

    private Button mBtnBaic;
    private Button mBtnObject;

    private Messenger mServerMessenger;
    private Messenger mClientMessenger = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_TEST_BASIC:
                    Bundle mBundleBasic = msg.getData();
                    mBundleBasic.setClassLoader(getClass().getClassLoader());
                    Log.d(TAG,"server::MSG_TEST_BASIC::msg.arg1 = " + msg.arg1 + "::msg.objct = " + mBundleBasic.get("MSG_TEST_BASIC"));
                    break;
                case MSG_TEST_OBJECT:
                    Bundle mBundleObject = msg.getData();
                    mBundleObject.setClassLoader(getClass().getClassLoader());
                    Object mObjectData = mBundleObject.get("MSG_TEST_OBJECT");
                    TestObject mTestObject = null;
                    if(mObjectData instanceof TestObject){
                        mTestObject = (TestObject)mObjectData;
                    }
                    Log.d(TAG,"server::MSG_TEST_OBJECT::msg.objct = " + mTestObject);
                    break;
            }
        }
    });

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

        Log.d(TAG,"client::onCreate");

        mBtnBaic = findViewById(R.id.btn_basic);
        mBtnObject = findViewById(R.id.btn_object);

        Intent mIntent = new Intent();
        mIntent.setComponent(new ComponentName("test.zxl.com.test_messenger_server","test.zxl.com.test_messenger_server.TestService"));
        bindService(mIntent,mServiceConnection, Context.BIND_AUTO_CREATE);

        mBtnBaic.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message message = Message.obtain();
                message.what = MSG_TEST_BASIC;
                Bundle mBundle = new Bundle();
                mBundle.putInt("MSG_TEST_BASIC",123);
                message.setData(mBundle);
                message.replyTo = mClientMessenger;
                try {
                    mServerMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });

        mBtnObject.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message message = Message.obtain();
                message.what = MSG_TEST_OBJECT;
                Bundle mBundle = new Bundle();
                TestObject mTestObject = new TestObject();
                TestChildObject mTestChildObject = new TestChildObject();
                mTestObject.mTestChildObject = mTestChildObject;
                mTestObject.testInt = 125;
                mTestObject.testStr="client";
                mTestObject.mTestChildObject.testInt = 126;
                mTestObject.mTestChildObject.testStr = "client_child";
                mBundle.putParcelable("MSG_TEST_OBJECT",mTestObject);
                message.setData(mBundle);
                message.replyTo = mClientMessenger;
                try {
                    mServerMessenger.send(message);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });


    }

    ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG,"client::onServiceConnected");
            mServerMessenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG,"client::onServiceDisconnected");
        }
    };
}

3.4客户端、服务端添加序列化对象TestObject、TestChildObject

package test.zxl.com.test_messenger.data;

import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.RequiresApi;

public class TestObject implements Parcelable {
    public int testInt;
    public String testStr = "";
    public TestChildObject mTestChildObject = null;

    public TestObject() {
    }

    protected TestObject(Parcel in) {
        testInt = in.readInt();
        testStr = in.readString();
        mTestChildObject = in.readParcelable(TestChildObject.class.getClassLoader());
    }

    public static final Creator<TestObject> CREATOR = new Creator<TestObject>() {
        @Override
        public TestObject createFromParcel(Parcel in) {
            return new TestObject(in);
        }

        @Override
        public TestObject[] newArray(int size) {
            return new TestObject[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(testInt);
        dest.writeString(testStr);
        dest.writeParcelable(mTestChildObject,flags);
    }

    @Override
    public String toString() {
        return "TestObject{" +
                "testInt=" + testInt +
                ", testStr='" + testStr + '\'' +
                ", mTestChildObject=" + mTestChildObject +
                '}';
    }
}
package test.zxl.com.test_messenger.data;

import android.os.Parcel;
import android.os.Parcelable;

public class TestChildObject implements Parcelable {
    public int testInt;
    public String testStr = "";

    public TestChildObject() {
    }

    public TestChildObject(Parcel in) {
        testInt = in.readInt();
        testStr = in.readString();
    }

    public static final Creator<TestChildObject> CREATOR = new Creator<TestChildObject>() {
        @Override
        public TestChildObject createFromParcel(Parcel in) {
            return new TestChildObject(in);
        }

        @Override
        public TestChildObject[] newArray(int size) {
            return new TestChildObject[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(testInt);
        dest.writeString(testStr);
    }

    @Override
    public String toString() {
        return "TestChildObject{" +
                "testInt=" + testInt +
                ", testStr='" + testStr + '\'' +
                '}';
    }
}
展开阅读全文

没有更多推荐了,返回首页