使用Messenger:
Messenger 可以在不同的进程传递 Message 对象,而我们可以在 Message 对象中放入我们所需要的数据,这样就能实现进程间通信了。首先我们来看一个图了解一下:
由图可以看出,我们可以在客户端发送一个Message给服务端,在服务端的handler中会接收到客户端的消息,然后进行对应的处理,处理完成后,再将结果等数据封装成Message,发送给客户端,客户端的handler中会接收到处理的结果。
以下是如何使用Messenger的步骤:
服务端接收客户端数据:
1. Service需要实现一个Hanlder,用以处理从客户端收到的消息
2.用该Handler创建一个Messenger对象,Messenger对象内部会引用该Handler对象
3. 用创建好的Messenger对象获得一个IBinder实例,并且将该IBinder通过Service的onBind方法返回给各个客户端
客户端向服务端发送数据:
4. 客户端通过收到的IBinder对象实例化一个Messenger对象,该Messenger内部指向Service中的Handler。客户端通过该Messenger对象就可以向Service中的Hanlder发送消息。
5. Service中的Hanlder收到消息后,在Handler中的handleMessage方法中处理消息。
6. 通过上面的第4步与第5步,就完成了客户端向Service发送消息并且Service接收到消息的单向通信过程,即客户端 -> Service。
如果要实现Service向客户端回消息的通信过程,即Service -> 客户端,那么前提是在客户端中也需要像Service一样内部维护有一个指向Handler的Messenger。当在第4步中客户端向Service发送信息时,将Message的replyTo属性设置为客户端自己的Messenger。这样在第5步Service在Handler的handleMessage中处理收到的消息时,可以通过Message的Messenger再向客户端发送Message,这样客户端内维护的Handler对象就会收到来自于Service的Message,从而完成Service向客户端发送消息且客户端接收到消息的通信过程。
具体实例:
(1)服务端代码:
public class MessengerService extends Service {
private static final String TAG = "MessengerService";
// 消息处理messengerHandler,处理来自客户端的消息
private ServiceMessengerHandler messengerHandler = new ServiceMessengerHandler();
// 指向handler的服务端Messenger
private Messenger mServiceMessenger = new Messenger(messengerHandler);
public MessengerService() {
}
@Override
public IBinder onBind(Intent intent) {
return mServiceMessenger.getBinder();
}
public static class ServiceMessengerHandler extends Handler{
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
// 取出客户端的消息内容
Bundle clientBundle = msg.getData();
String clientMessage = clientBundle.getString("client");
Log.i(TAG, "客户端的消息是:" + clientMessage);
// 新建一个Message对象,作为回复客户端的对象(Service回复的消息)
Message serviceToClientMsg = Message.obtain();
Bundle serviceBundle = new Bundle();
serviceBundle.putString("service", "你好,客户端很高兴认识你!");
serviceToClientMsg.setData(serviceBundle);
// 获取客户端携带过来的Messenger对象
Messenger mClientMessenger = msg.replyTo;
try {
// 回复消息给客户端
mClientMessenger.send(serviceToClientMsg);
} catch(RemoteException e) {
e.printStackTrace();
}
}
}
}
(2)客户端代码
public class MessengerActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MessengerActivity";
// 客户端的消息处理器
private ClientMessengerHandler clientMessengerHandler = new ClientMessengerHandler();
// 指向handler的客户端的Messenger
private Messenger mClientMessenger = new Messenger(clientMessengerHandler);
private static class ClientMessengerHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Bundle serviceBundle = msg.getData();
String serviceMessage = serviceBundle.getString("service");
Log.i(TAG, "服务端回复的消息是:" + serviceMessage);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.bindService:
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
break;
case R.id.unBindService:
unbindService(mConnection);
break;
default:
break;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// 获取服务端关联的Messenger对象
Messenger mServiceMessenger = new Messenger(iBinder);
// 创建客户端向服务端传递消息的Message
Message clientToServiceMsg = Message.obtain();
Bundle clientBundle = new Bundle();
clientBundle.putString("client", "你好,服务器,我是客户端!");
clientToServiceMsg.setData(clientBundle);
// 在message中添加一个服务端回复客户端的客户端Messenger对象
clientToServiceMsg.replyTo = mClientMessenger;
try {
mServiceMessenger.send(clientToServiceMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
}
}
(3)客户端布局文件
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MessengerActivity">
<Button
android:id="@+id/bindService"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/unBindService"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.constraintlayout.widget.ConstraintLayout>