Android 基于Message的进程间通信
注:参考链接 https://blog.csdn.net/lmj623565791/article/details/47017485
通过两个apk演示,一个apk是Server端,一个是Client端;
服务端
package com.example.messengerservice;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
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.util.Log;
public class MessengerService extends Service {
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
private static final int MSG_SUM = 0x110;
//最好换成HandlerThread的形式
private Messenger mMessenger = new Messenger(new Handler()
{
@Override
public void handleMessage(Message msgfromClient)
{
Message msgToClient = Message.obtain(msgfromClient);//返回给客户端的消息
Bundle bundle2=msgToClient.getData();//获取Bundle对象
switch (msgfromClient.what)
{
//msg 客户端传来的消息
case MSG_SUM:
msgToClient.what = MSG_SUM;
try
{
//模拟耗时
Thread.sleep(2000);
// msgToClient.arg2 = msgfromClient.arg1 + msgfromClient.arg2;
Bundle bundle=new Bundle();
bundle.putString("name",bundle2.getString("name"));
bundle.putString("sex",bundle2.getString("sex"));
Message message=new Message();
message.setData(bundle);
message.what=MSG_SUM;
msgfromClient.replyTo.send(message);
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (RemoteException e)
{
e.printStackTrace();
}
break;
}
super.handleMessage(msgfromClient);
}
});
}
服务端别忘了注册服务
<service
android:name=".MessengerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.messengerservice"></action>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
客户端
package com.example.viewcirclebar;
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 android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private TextView tv;
private static final String TAG = "MainActivity";
private static final int MSG_SUM = 0x110;
private LinearLayout mLayout;
private Messenger messenger=new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case MSG_SUM:
Bundle bundle2=msg.getData();
// TextView tv = (TextView) mLayout.findViewById(msg.what);
// tv.setText(tv.getText() + "=>" + msg.arg2);
mTvState.setText(bundle2.getString("name")+"==="+bundle2.getString("sex"));
break;
}
}
});
//显示连接状态
private TextView mTvState;
private Messenger mService;
private boolean isConn;
private int mA;
private ServiceConnection mConn = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = new Messenger(service);
isConn = true;
mTvState.setText("connected!");
}
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
isConn = false;
mTvState.setText("disconnected!");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTvState=findViewById(R.id.tv);
bindServiceInvoked();
Button button= findViewById(R.id.button);
mLayout=findViewById(R.id.mLayout);
button.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
try
{
// int a = mA++;
// int b = (int) (Math.random() * 100);
//
// //创建一个tv,添加到LinearLayout中
// TextView tv = new TextView(MainActivity.this);
// tv.setText(a + " + " + b + " = caculating ...");
// tv.setId(a);
// mLayout.addView(tv);
// Message msgFromClient = Message.obtain(null, MSG_SUM, a, b);
Bundle bundle=new Bundle();
bundle.putString("name","only");
bundle.putString("sex","男");
Message message=new Message();
message.setData(bundle);
message.what=MSG_SUM;
Message msgFromClient = Message.obtain(message);
msgFromClient.replyTo = messenger;
if (isConn)
{
//往服务端发送消息
mService.send(msgFromClient);
}
} catch (RemoteException e)
{
e.printStackTrace();
}
}
});
}
private void bindServiceInvoked()
{
Intent intent = new Intent();
intent.setPackage("com.example.messengerservice");
intent.setAction("com.example.messengerservice");
bindService(intent, mConn, Context.BIND_AUTO_CREATE);
Log.e(TAG, "bindService invoked !");
}
@Override
protected void onDestroy()
{
super.onDestroy();
unbindService(mConn);
}
}
xml布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
android:id="@+id/mLayout"
android:animateLayoutChanges="true">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="123"
android:textSize="20dp"/>
</LinearLayout>
代码就这样了,看一下服务端代码
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
服务端中onBind(Intent intent)方法中的返回,这里通过getBinder()返回的IBinder,点击进去看到
public IBinder getBinder() {
return mTarget.asBinder();
}
可以看到返回的是mTarget.asBinder();
mTarget是哪来的呢?
我们前面去构造mMessenger对象的代码:new Messenger(new Handler());点击Messenger
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
可以看到mTarget是Handler返回出来的,在点击看getIMessenger(),如何点击不了的我们可以点击Handler在其中全局查找到getIMessenger();
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
这里看到mTarget是MessengerImpl()的一个对象,那么asBinder实际上是返回this,也就是MessengerImpl对象;
这是个内部类,可以看到继承自IMessenger.Stub,然后实现了一个send方法,该方法就是将接收到的消息通过 Handler.this.sendMessage(msg);发送到handleMessage方法。
这里可以看出我们传统写aidl文件有点一样,aapt给我们生成什么,生成IXXX.Stub类,然后我们服务端继承IXXX.Stub实现接口中的方法。
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
看到这,你应该明白了,Messenger并没有什么神奇之处,实际上,就是依赖该aidl文件生成的类,继承了IMessenger.Stub类,实现了send方法,send方法中参数会通过客户端传递过来,最终发送给handler进行处理。
客户端代码
客户端首先通过onServiceConnected拿到sevice(Ibinder)对象
private ServiceConnection mConn = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = new Messenger(service);
isConn = true;
mTvState.setText("connected!");
}
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
isConn = false;
mTvState.setText("disconnected!");
}
};
而,我们的代码中是
mService = new Messenger(service);
跟进去,你会发现:
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
客户端与服务端通信,实际上和我们平时的写法没有任何区别,通过编写aidl文件,服务端onBind利用Stub编写接口实现返回;客户端利用回调得到的IBinder对象
private void bindServiceInvoked()
{
Intent intent = new Intent();
intent.setPackage("com.example.messengerservice");
intent.setAction("com.example.messengerservice");
bindService(intent, mConn, Context.BIND_AUTO_CREATE);
Log.e(TAG, "bindService invoked !");
}
这里提一下,这里如何没有设置setPackage()方法的话会报错java.lang.IllegalArgumentException: Service Intent must be explicit: Intent,而之前的参考链接没有的。
这是我往服务器端发送的数据
Bundle bundle=new Bundle();
bundle.putString("name","only");
bundle.putString("sex","男");
Message message=new Message();
message.setData(bundle);
message.what=MSG_SUM;
Message msgFromClient = Message.obtain(message);
msgFromClient.replyTo = messenger;
我们看一下 Message.obtain(message)
public static Message obtain(Message orig) {
Message m = obtain();
m.what = orig.what;
m.arg1 = orig.arg1;
m.arg2 = orig.arg2;
m.obj = orig.obj;
m.replyTo = orig.replyTo;
m.sendingUid = orig.sendingUid;
if (orig.data != null) {
m.data = new Bundle(orig.data);
}
m.target = orig.target;
m.callback = orig.callback;
return m;
}
看到这,知道我们实际可以通过我们常用的Message 传参,其实我们只要稍加修改就能传递其他的参数类型,可以多看下其他obtain()的方法
服务端与客户端通信
那么,客户端与服务端通信的确没什么特殊的地方,我们完全也可以编写个类似的aidl文件实现;那么服务端是如何与客户端通信的呢?
还记得,客户端send方法发送的是一个Message,这个Message.replyTo指向的是一个mMessenger,我们在Activity中初始化的。
那么将消息发送到服务端,肯定是通过序列化与反序列化拿到Message对象,我们看下Message的反序列化的代码:
private void readFromParcel(Parcel source) {
what = source.readInt();
arg1 = source.readInt();
arg2 = source.readInt();
if (source.readInt() != 0) {
obj = source.readParcelable(getClass().getClassLoader());
}
when = source.readLong();
data = source.readBundle();
replyTo = Messenger.readMessengerOrNullFromParcel(source);
sendingUid = source.readInt();
}
主要看replyTo,调用的是Messenger.readMessengerOrNullFromParcel
public static Messenger readMessengerOrNullFromParcel(Parcel in) {
IBinder b = in.readStrongBinder();
return b != null ? new Messenger(b) : null;
}
public static void writeMessengerOrNullToParcel(Messenger messenger,
Parcel out) {
out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
: null);
}
通过上面的writeMessengerOrNullToParcel可以看到,它将客户端的messenger.mTarget.asBinder()对象进行了恢复,客户端的message.mTarget.asBinder()是什么?
客户端也是通过Handler创建的Messenger,于是asBinder返回的是:
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
public IBinder getBinder() {
return mTarget.asBinder();
}
那么asBinder,实际上就是MessengerImpl extends IMessenger.Stub中的asBinder了。
#IMessenger.Stub
@Override
public android.os.IBinder asBinder()
{
return this;
}
其实返回的就是MessengerImpl对象自己。到这里可以看到message.mTarget.asBinder()其实返回的是客户端的MessengerImpl对象。
最终,发送给客户端的代码是这么写的:
msgfromClient.replyTo.send(msgToClient);
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
这个mTarget实际上就是对客户端的MessengerImpl对象的封装,那么send(message)(屏蔽了transact/onTransact的细节),这个message最终肯定传到客户端的handler的handleMessage方法中。
注:转载链接 https://blog.csdn.net/lmj623565791/article/details/47017485