Messenger
标签: 跨进程通讯
目录
在日常开发中,很少遇到跨进程通讯的需求。所以跨进程通讯这一块一直是我的痛点,准备面试的过程中,又一次揭开伤疤,痛定思痛,终于下定决心解决这一盲区。
我们在学习中,经常说到跨进程通讯,立马想起AIDL
,在上一篇Blog中对AIDL以及定向tag做了还算详细的整理,如果有兴趣可以复习一下 学习AIDL,这一篇差不多了
首先
无耻的引入一下 lypeer的博文:
大家看到Messenger可能会很轻易的联想到Message,然后很自然的进一步联想到Handler——没错,Messenger的核心其实就是Message以及Handler来进行线程间的通信。下面讲一下通过这种方式实现IPC的步骤:
- 服务端实现一个Handler,由其接受来自客户端的每个调用的回调
- 使用实现的Handler创建Messenger对象
- 通过Messenger得到一个IBinder对象,并将其通过onBind()返回给客户端
- 客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Message 对象发送给服务
- 服务端在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message
1. 服务端配置
1.1 实现Handler
实现Handler不需要多说,在没有RxJava的日子里,不知道写过多少遍,直接上代码:
@SuppressLint("HandlerLeak")
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
Toast.makeText(MessagerService.this, "发送的信息是 0", Toast.LENGTH_SHORT).show();
break;
case 1:
Bundle data = msg.getData();
String str = data.getString("data");
Toast.makeText(MessagerService.this, "收到的消息是 1 : " + str, Toast.LENGTH_SHORT).show();
break;
}
}
};
1.2 创建Messenger
final Messenger messenger = new Messenger(handler);
1.3 设置onBind()方法返回值
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
1.4 服务端整体代码
public class MessagerService extends Service {
public MessagerService() {
}
@SuppressLint("HandlerLeak")
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
Toast.makeText(MessagerService.this, "发送的信息是 0", Toast.LENGTH_SHORT).show();
Log.e(TAG, "handleMessage: 发送的信息是 0");
break;
case 1:
Bundle data = msg.getData();
String str = data.getString("data");
Toast.makeText(MessagerService.this, "收到的消息是 1 : " + str, Toast.LENGTH_SHORT).show();
Log.e(TAG, "handleMessage: 收到的消息是 1 : " + str);
break;
}
}
};
final Messenger messenger = new Messenger(handler);
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
1.6 配置
想要跨进程调用Service,需要在AndroidManifest.xml
进行配置:
<service
android:name=".MessagerService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.martin.messagerserver" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
2. 客户端实现
2.1 绑定服务
private void connectService() {
Intent intent = new Intent()
.setAction("com.martin.messagerserver")
.setPackage("com.martin.messagerserver");
bindService(intent, connection, BIND_AUTO_CREATE);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnect = true;
messenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
isConnect = false;
}
};
2.2 设置点击事件
public void sendZero(View view) {
if (isConnect && messenger != null) {
Message msg = Message.obtain();
msg.what = 0;
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(this, "0 发送失败了", Toast.LENGTH_SHORT).show();
Log.e(TAG, "sendZero: 0 发送失败了");
}
} else {
Toast.makeText(this, "0 并没有连接上", Toast.LENGTH_SHORT).show();
Log.e(TAG, "sendZero: 0 并没有连接上");
}
}
public void sendOne(View view) {
if (isConnect && messenger != null) {
Message obtain = Message.obtain();
obtain.what = 1;
Bundle data = new Bundle();
data.putString("data", "我是从客户端发过来的哟!再次测试");
obtain.setData(data);
try {
messenger.send(obtain);
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(this, "1 发送失败咯", Toast.LENGTH_SHORT).show();
Log.e(TAG, "sendOne: 1 发送失败咯");
}
} else {
Toast.makeText(this, "1 未连接", Toast.LENGTH_SHORT).show();
Log.e(TAG, "sendOne: 1 未连接");
}
}
2.3 客户端全代码
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private boolean isConnect = false;
private Messenger messenger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void sendZero(View view) {
if (isConnect && messenger != null) {
Message msg = Message.obtain();
msg.what = 0;
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(this, "0 发送失败了", Toast.LENGTH_SHORT).show();
Log.e(TAG, "sendZero: 0 发送失败了");
}
} else {
Toast.makeText(this, "0 并没有连接上", Toast.LENGTH_SHORT).show();
Log.e(TAG, "sendZero: 0 并没有连接上");
}
}
public void sendOne(View view) {
if (isConnect && messenger != null) {
Message obtain = Message.obtain();
obtain.what = 1;
Bundle data = new Bundle();
data.putString("data", "我是从客户端发过来的哟!再次测试");
obtain.setData(data);
try {
messenger.send(obtain);
} catch (RemoteException e) {
e.printStackTrace();
Toast.makeText(this, "1 发送失败咯", Toast.LENGTH_SHORT).show();
Log.e(TAG, "sendOne: 1 发送失败咯");
}
} else {
Toast.makeText(this, "1 未连接", Toast.LENGTH_SHORT).show();
Log.e(TAG, "sendOne: 1 未连接");
}
}
@Override
protected void onStart() {
super.onStart();
connectService();
}
/**
* 连接服务
*/
private void connectService() {
Intent intent = new Intent()
.setAction("com.martin.messagerserver")
.setPackage("com.martin.messagerserver");
bindService(intent, connection, BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// 解绑 service
unbindService(connection);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnect = true;
messenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
isConnect = false;
}
};
}
总结
貌似也没讲解什么,就是贴了代码。
算了,直接贴源码吧,CSDN源码最低设置2分,如果有需要可以留下邮箱,我看到会即使回的。