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 + '\'' + '}'; }}
标签:通信,Messenger,test,import,Android,os,public,android 来源: https://blog.51cto.com/u_15091798/2782929