前面两篇文章中已经介绍了两种实现进程间通信的方式,那是不是只有这两种方式实现进程间通信呢?当然不是,还有更好的实现方式,那就是Messenger。本篇文章将带领大家一起来学习下Messenger.
没有看我写的上面两篇文章的同学,建议先去看下上面两篇文章,以更好的理解。
什么是基于消息的进程通信?
该图片是引用自弘扬大神的博客
其实基于消息的进程通信就是客户端通过Handler发送一条Message,服务端收到这条Message然后获取到客户端的值,服务端进行处理,再将结果封装成Message传递给客户端。通过这种方式实现aidl有什么好处呢?
- 不用再写aidl文件了(很多同学一提到aidl就头疼)
- 基于Message,这个大家已经很熟悉了
接下来我们通过代码详细的介绍下。
1,服务端,我们定义一个MessengerService.java的Service,代码如下:
package com.wms.github.aidl.server;
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 android.util.Log;
/**
* Created by 王梦思 on 2017/5/25.
*/
public class MessengerService extends Service {
private static final String TAG = "MessengerService";
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message clientMsg) {
if (clientMsg.what == 0x001) {
//注意这个里clientMsg是客户端发送过来的消息
Bundle bundle = (Bundle) clientMsg.obj;
String str = bundle.getString("str");
str = str.toUpperCase();
//服务端处理完逻辑后,将数据通过Messeage的方式传递给客户端
Message message = Message.obtain();
Bundle sendBundle = new Bundle();
sendBundle.putString("str", str);
message.obj = sendBundle;
message.what = 0x001;
try {
//将消息发送到客户端
clientMsg.replyTo.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
super.handleMessage(clientMsg);
}
});
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind...");
//这里不能返回null,必须要返回我们创建的Binder对象
return messenger.getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind...");
return super.onUnbind(intent);
}
@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "onStart...");
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand...");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
Log.e(TAG, "onCreate...");
super.onCreate();
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy...");
super.onDestroy();
}
}
服务端就一个Service,可以看到代码相当的简单,只需要去声明一个Messenger对象,然后onBind方法返回messenger.getBinder();
然后坐等客户端将消息发送到handleMessage想法,根据message.what去判断进行什么操作,然后做对应的操作,最终将结果通过 clientMsg.replyTo.send(),这里注意一定要调用clientMsg.replyTo.send()去发送消息,不然客户端接收不到。
注册MessengerService
<service
android:name="com.wms.github.aidl.server.MessengerService"
android:exported="true">
<intent-filter>
<action android:name="com.wms.github.aidl.server.MessengerService"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
2,客户端。在客户端我新建一个MessengerActivity.java,代码如下:
package com.wms.github.aidl.client;
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.util.Log;
import android.view.View;
import android.widget.EditText;
/**
* Created by 王梦思 on 2017/5/25.
*/
public class MessengerActivity extends MainActivity {
private EditText mEditText;
private Messenger mService;
private Messenger clientMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x001) {
Bundle bundle = (Bundle) msg.obj;
mEditText.setText(bundle.getString("str"));
}
super.handleMessage(msg);
}
});
private ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//当绑定成功后调用
Log.e("MainActivity", "onServiceConnected...");
mService = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("MainActivity", "onServiceDisconnected...");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = (EditText) findViewById(R.id.id_edittext);
findViewById(R.id.bind).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService();
}
});
findViewById(R.id.unbind).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unBindService();
}
});
findViewById(R.id.invokeServer).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
invokeServer();
}
});
}
/**
* 绑定服务
*/
public void bindService() {
Intent intent = new Intent();
intent.setAction("com.wms.github.aidl.server.MessengerService");
//Android 5.0以上必须要加这句代码,不然报错
intent.setPackage("com.wms.github.aidl.server");
bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
}
public void unBindService() {
unbindService(mServiceConn);
}
public void invokeServer() {
String inputStr = mEditText.getText().toString().trim();
try {
Message message = Message.obtain();
message.what = 0x001;
Bundle bundle = new Bundle();
bundle.putString("str",inputStr);
message.obj = bundle;
//将消息的回应设置为clientMessenger,这样客户端发送消息就能在客户端收到了。
message.replyTo = clientMessenger;
mService.send(message);
} catch (RemoteException e) {
//这里会抛出远程异常
e.printStackTrace();
}
}
}
布局文件和上篇文章中一样。
MessengerActivity.java中代码也很简单,就是绑定一个服务,然后再onServiceConnect中实例化一个Messenger,这个Messenger和MessengerActivity中属性clientMessenger不一样,因为这个Messenger实例化的时候把Binder驱动传递进来了。所以当客户端调用mService.send(message);
后,服务端将会收到客户端传递过来的数据,服务端处理完之后,返回到Client端的clientMessenger中的Handler的handleMessage方法中,这样就完成了客户端和服务端的通信。
效果图:
当我们点击调用服务端转换后,服务端就把大写字母回传给客户端。以上就是简单的Messenger的使用,肯定很多人有疑问,为什么这样可以实现进程间的通信呢?下面我将带领大家一起来从源码的角度来看看。
1,先分析服务端,服务端中onBind()方法里面我们返回了messenger.getBinder();
很简单,就一行代码,我们进入Messenger的内部看下getBinder内部到底做了什么事情
/**
* Retrieve the IBinder that this Messenger is using to communicate with
* its associated Handler.
*
* @return Returns the IBinder backing this Messenger.
*/
public IBinder getBinder() {
return mTarget.asBinder();
}
getBinder方法也很简单,也就一行代码。这里mTarget是什么呢?查看下源码,private final IMessenger mTarget;
可以看出mTarget是一个IMessenger对象,mTarget赋值是在我们实例化clientMessenger对象的时候Messenger构造方法里面。我们再来看看Messenger的构造方法
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
* been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
继续跟进到Handler内部的getImessenger方法
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
恍然大悟,原来mTarget其实是一个MessengerImpl对象。再回到Messenger中的getBinder方法,其实就是调用了MessengerImpl内部的asBinder方法,我们进入到MessengerImpl中的asBinder中看看其内部做了什么事情。
MessengerImpl原来是继承自IMessenger.Stub,是不是很熟悉?这不又回到了我们前面的文章中通过aidl实现进程通信的了么?原来Android内部已经帮我们实现了一个IMessenger.aidl文件,这个文件位于framework中的platform_frameworks_base/core/java/android/os/IMessenger.aidl,大家可以下载framework源代码去查看下。由于aidl代码较少,我下面贴出IMessenger.aidl内部代码如下:
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger {
void send(in Message msg);
}
哇,好简答,就一个send方法,send方法里面传递的是一个Message对象。所以这一切又回到了我们前面所说的aidl进行进程通信的内容了。如果不明白的可以看我之前写过的一篇文章 基于aidl实现的进程通信
2,接下来我们分析下客户端源代码
当客户端调用绑定服务的时候,会调用onServiceConnect方法
private ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//当绑定成功后调用
Log.e("MainActivity", "onServiceConnected...");
mService = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("MainActivity", "onServiceDisconnected...");
}
};
在onServiceConnected中我们实例化了一个Messenger,并且传递了一个IBinder对象,这个IBinder对象就是一直说的Binder驱动。我们进入Messenger这个构造函数中看看:
/**
* Create a Messenger from a raw IBinder, which had previously been
* retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
是不是又很熟悉?这不就是我们在 基于aidl实现的进程通信 中onSeviceConnect方法实现的一样么?
综上分析客户端和服务端的源代码,其实和我们写aidl完全一样,没有任何区别,Messenger底层其实就是基于aidl来实现的进程通信,只是Android内部已经给我们写好了一个IMessnger.aidl文件,不需要我们手动实现了。
到此,我们就已经分析完了源码了,如果还是不明白的同学建议去翻看下Messenger的源码,并不复杂,到此Android中实现进程通信的常用方式已经介绍完了。