1. 简介
IPC:进程间通信(Inter Process Communication),指两个进程之间进行数据交换
- 进程与线程
进程:一个执行单元,移动设备上的一个应用或程序。一个进程可以包含多个线程。Android中最有特色的进程间通信方式是Binder
线程:CPU调度的最小单元
多进程是进程间通信的前提,IPC应用场景:
- 一个应用采取多进程模式实现,应用自身需要传递数据
- 两个应用需要传递数据。ContentProvider
2.一个应用多个进程
一个应用开启多进程的方式:
- 四大组件(Activity、Service、BroadcastReceiver、ContentProvider)在Manifest中添加 android:process属性
- JNI在native层去fork一个新进程
2.1 android:process实现多进程
MainActivity,SecondActivity、ThirdActivity在Manifest中配置如下:
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:label="@string/app_name"
android:process=":remote">
</activity>
<activity
android:name=".ThirdActivity"
android:process="com.jieqiong.ipc.remote">
</activity>
点击MainActivity 的按钮,跳转至SecondActivity
点击SecondActivity的按钮,跳转至ThirdActivity
通过Android Device Monitor查看进程号
或者通过 adb shell ps | grep jieqiong.ipc 查看
u0_a201 12288 532 1726436 46032 SyS_epoll_ 0000000000 S com.jieqiong.ipc
u0_a201 12788 532 1727484 48580 SyS_epoll_ 0000000000 S com.jieqiong.ipc:remote
u0_a201 13030 532 1737260 43528 SyS_epoll_ 0000000000 S com.jieqiong.ipc.remote
启动了3个进程,进程号分别为12288,12788,13030
SecondActivity进程名为:com.jieqiong.ipc:remote
ThirdActivity进程名为:com.jieqiong.ipc.remote
android:process
- 以 : 开头,如 android:process=”:remote”,是当前应用的私有进程,其他应用的组件 不可以跟它跑在同一个进程。
- 不以 : 开头,如 android:process=”com.jieqiong.ipc.remote”,属于全局进程,其他应用通过shareUID方式和它跑在同一个进程中。
Android中两个应用通过ShareUID方式跑在同一个进程,要求签名相同,可以访问对方的私有数据,如data目录,组件信息,内存数据等。
Android每个应用都会有一个唯一的UID,具有相同UID的应用才能共享数据。
2.2 android:process存在的问题
定义UserManager,添加静态变量 userId = 1
public class UserManager {
public static int userId = 1;
}
MainActivity中将 userId 设为2
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UserManager.userId = 2;
String processName = Utils.getProcessName(getApplicationContext(), Process.myPid());
Log.d("MainActivity", "### processName = " + processName + ", UserManager.userId = " + UserManager.userId);
Button btnMain = (Button) findViewById(R.id.btn_Main);
btnMain.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
});
}
}
Utils
public class Utils {
public static String getProcessName(Context cxt, int pid) {
ActivityManager am = (ActivityManager) cxt
.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
if (runningApps == null) {
return null;
}
for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {