1. 背景
最近在看任玉刚老师的《Android开发艺术探索》,看到了 Messenger,觉得挺有意思的,写个 Demo 练习一下,同时根据 Messenger 可以延伸到其他知识点,比如Android的Binder通信机制,AIDL等知识点,本文算是 Messenger 初探。
1.1 Messenger 介绍
首先肯定要看一下官方对于 Messenger 的介绍。
/**
* 引用 Handler, 可以用其来发送 Message 信息。
* 允许跨进程来实现基于信息的通讯,通过在一个进程中创建一个 Messenger 对象,并且关联一个 Handler 对象,然后将消息传递给另外一个进程。
* 注意:其实现只是对 Binder 一个简单的包装,用于执行通信。这意味着从语义上来说:
* 这个类不影响进程的生命周期管理,如果的进程因为任何原因离开,连接将中断,等等,你必须使用一些更高级的组件来告诉系统您的流程需要继续运行。
*/
public final class Messenger implements Parcelable {
private final IMessenger mTarget;
/**
* 创建一个指定(关联)了一个 Handler 对象的 Messenger 对象。
* 通过该 Messenger 发送的任何消息都会被指定的 Handler 所接收,就像直接调用 Handler.sendMessage(Message)一样
*
* @param target 传入一个用于接受消息的 Handler对象。
*/
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
Messenger 译为信使,用于在不同的进程间传递 Message 信息,是 Service服务端与 Activity客户端之间通信的桥梁。
2. 简单例子Demo
简单的例子说明:首先创建一个服务端,可以让其处于额外的进程中,其次创建一个客户端,也就是我们的Activity,点击发送信息按钮后,客户端向服务端发送信息,并且服务端在接收到信息后,返回信息回给客户端。
2.1 创建服务端
创建一个服务端,取名为 MessengerService,并在清单文件中设置属性,让其处以额外的进程中,代码如下:
public class MessengerService extends Service {
private static final String TAG = "MessengerService";
public static final int MSG_FROM_SERVICE = 2;
public static final String SERVICE_REPLY_MSG_KEY = "SERVICE_REPLY_MSG";
private Messenger mMessenger = new Messenger(new MyHandler());
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
public static class MyHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msgFromClient) {
super.handleMessage(msgFromClient);
Bundle sendByClientBundle = msgFromClient.getData();
String clientMsg = sendByClientBundle.getString(MessengerServiceTestActivity.CLIENT_SEND_MSG_KEY);
Log.e(TAG, "client send message: " + clientMsg);
switch (msgFromClient.what) {
case MessengerServiceTestActivity.MSG_FROM_CLIENT:
try {
//模拟耗时4秒,服务端回应信息给客户端
Thread.sleep(4000);
Message replyClientMsg = new Message();
replyClientMsg.what = MSG_FROM_SERVICE;
Bundle bundle = new Bundle();
bundle.putString(SERVICE_REPLY_MSG_KEY, "My Name is Jere");
replyClientMsg.setData(bundle);
//回应消息给客户端
msgFromClient.replyTo.send(replyClientMsg);
} catch (InterruptedException | RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
}
在清单文件中设置该服务,并设置其 process 属性,让其处于额外的进程中,如newprocess。
<service
android:name=".messenger.MessengerService"
android:enabled="true"
android:exported="true"
android:process=":newprocess"/>
这样设置好后 MessengerService 就处在了 com.example.servicetest:newprocess 进程中。
2.2 创建客户端
创建一个客户端,取名为:MessengerServiceTestActivity,代码如下:
public class MessengerServiceTestActivity extends AppCompatActivity {
private static final String TAG = "MessengerServiceTestActivity";
public static final int MSG_FROM_CLIENT = 1;
public static final String CLIENT_SEND_MSG_KEY = "CLIENT_SEND_MSG";
private Messenger mMessenger;
private boolean isBoundService;
private Messenger mReplyToMessenger = new Messenger(new ServiceReplyToMessengerHandler());
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//利用服务端返回的 IBinder,新创建一个Messenger对象
mMessenger = new Messenger(service);
isBoundService = true;
Log.d(TAG, "onServiceConnected: ");
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBoundService = false;
Log.d(TAG, "onServiceDisconnected: ");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger_service_test);
//点击按钮,客户端向服务端发送信息,并指定了用于接收服务端返回信息的 Messenger 对象
Button sendMsgBtn = findViewById(R.id.send_message_btn);
sendMsgBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message message = new Message();
message.what = MSG_FROM_CLIENT;
Bundle sendToServiceBundle = new Bundle();
sendToServiceBundle.putString(CLIENT_SEND_MSG_KEY, "Hi! What's your name!");
message.setData(sendToServiceBundle);
//指定用于接收服务端返回信息的 Messenger
message.replyTo = mReplyToMessenger;
try {
//通过调用 Messenger 中的 send() 方法,将消息发送给服务端
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onStart() {
super.onStart();
//绑定服务
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
//如果绑定了服务,则解绑服务
if (isBoundService) {
unbindService(serviceConnection);
isBoundService = false;
}
}
public static class ServiceReplyToMessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MessengerService.MSG_FROM_SERVICE:
Bundle serviceReplyBundle = msg.getData();
String name = serviceReplyBundle.getString(MessengerService.SERVICE_REPLY_MSG_KEY);
Log.e(TAG, "receiver service message info: " + name);
break;
default:
break;
}
}
}
}
同时看一下其在清单文件中的配置:
<activity android:name=".messenger.MessengerServiceTestActivity"/>
没有额外的为客户端设置进程属性,这是客户端位于 com.example.servicetest 进程中。
2.3 测试
点击按钮后,客户端向服务端发送 “Hi! What’s your name!”,服务端在接收到信息后,返回给客户端 “My Name is Jere”,注意看 LOG 信息,其处于的进程是不一样的。
//服务端接收到客户端发送过来的信息
com.example.servicetest:newprocess E/MessengerService: client send message: Hi! What's your name!
//客户端接收到服务端返回的信息
com.example.servicetest E/MessengerServiceTestActivity: receiver service message info: My Name is Jere
End~
本文只是简单的对 Messenger 进行初探~