前言
Android 中跨进程通信的方式比较多,比如可以通过在 Intent 中附加 extras 来传递信息,或者通过共享文件的方式来共享数据,还可以采用 Binder 方式来跨进程通信,另外,ContentProvider 天生就是支持跨进程访问的,因此我们也可以采用它来进行 IPC。此外,通过网络通信也是可以实现数据传递的,所以 Socket 也是可以实现 IPC 的。今天我们先来介绍一下通过使用 Bundle 的方式进行 IPC。
使用 Bundle
我们知道四大组件中的三大组件(Activity、Service、BroadcastReceiver)都是支持在 Intent 中传递 Bundle 数据的,由于 Bundle 实现了 Parcelable 接口,所以它可以方便地在不同的进程间传输。
基于这一点,当我们在一个进程中启动了另一个进程的 Activity、Service 和 Receiver,我们就可以在 Bundle 中附加我们需要传输给远程进程的信息并通过 Intent 发送出去。当然,我们传输的数据必须能够被序列化,比如基本类型、实现了 Parcelable 接口的对象、实现了 Serializable 接口的对象以及一些 Android 支持的特殊对象。
A 进程中 MainActivity:
Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondActivity.class);
User user = new User(0, "jake");
intent.putExtra("extra_user", (Serializable) user);
startActivity(intent);
B 进程中 SecondActivity:
@Override
protected void onResume() {
super.onResume();
User user = (User) getIntent().getSerializableExtra("extra_user");
Log.d(TAG, "user:" + user.toString());
}
其中 User 类:
public class User implements Serializable {
private static final long serialVersionUID = 519067123721295773L;
public int userId;
public String userName;
public User() {
}
public User(int userId, String userName) {
this.userId = userId;
this.userName = userName;
}
@Override
public String toString() {
return String.format(
"User:{userId:%s, userName:%s}",userId, userName);
}
}
Bundle 不支持的类型无法通过它在进程间传递。
除了直接传递数据这种典型的使用场景,它还有一种特殊的使用场景。比如 A 进程正在进行一个计算,计算完成后它要启动 B 进程的一个组件并把计算结果传递给 B 进程,可是遗憾的是这个计算结果不支持放入到 Bundle 中,因此无法通过 Intent 来传输,这个时候如果我们使用其他的 IPC 方式就会略显复杂。
可以考虑如下方式:
我们通过 Intent 启动 B 的一个 Service 组件(比如 IntentService),让 Service 在后台进行计算,计算完毕后再启动 B 进程中真正要启动的目标组件,由于 Service 也运行在 B 进程中,所以目标组件就可以直接获取计算记过,这样一来就轻松解决了跨进程的问题。这种方式的核心思想在于将原本需要在 A 进程的计算任务转移到 B 进程的后台 Service 中去执行,这样就成功地避免了进程间通信问题,而且只用了很小的代价。