Android使用Messenger跨进程通信教程
- 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的区别:
- -
- Messenger是以Handler为基础的,其封装了AIDL与Handler,使客户端与服务端交互看起来像是Handler、Message;而AIDL是跨进程调用对方提供的接口 。
- 由于一个Service对应一个Messenger,并对应一个Handler,所以其服务端在一个独立线程中处理消息队列中的消息请求,这个样多个客户端请求,其对应的同一个服务端要排队依次处理请求消息;而AIDL对应的Service,每接收到一个请求,则会新建一个线程单独处理,即不用排队等待处理消息。
由于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: 14563android.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 + '\'' +
'}';
}}