IPC 基础一 概念和多进程模式
IPC简介
IPC是Inter-process communication的缩写,含义是进程间通信或者叫跨进程通信,是指两个进程间进行数据交换的过程。
进程和线程。
1、线程:
线程是CPU调度的最小单眼,线程是一种有限的系统资源。
2、进程:
进程指的是一个执行单元,在PC或移动设备上指一个程序或者一个应用。
3、进程和线程的关系:
一个进程可以包含多个线程。但是一个进程中最多只能包含一个主线程,也就是UI线程。在主线程中不能进行耗时的操作,否则会导致应用无响应,也就是ANR(Application Not Responding),所以需要把一些耗时的操作放在子线程中执行。
Android中的多进程模式
开启多进程模式
正常情况下,在Android中多进程是指一个应用中存在多个进程的情况,所以下面讨论的大都是一个应用下的多个进程之间的通信。
Android中开启多进程的方式
1、在AndroidMenifest.xml文件中注册四大组件(Activity,Service,BroadCastReceiver,ContentProvider)时指定Android:process属性
2、通过JNI在native层去fork一个新的进程。这种方式是非常规的多进程方法,不是常用的创建多进程的方式。
创建多进程:
<activity android:name=".ipc_demo2.IpcEntryActivity" />
<activity
android:name=".ipc_demo2.OneActivity"
android:process=":remote" />
<activity
android:name=".ipc_demo2.TwoActivity"
android:process="com.ipc_demo2.remote" />
上面的例子分别为OneActivity和TwoActivity指定了process属性,并且它们的属性值不同,也就是说为当前应用开启了两个新的进程。注意,如果没有指定process就是工作在默认进程中,默认进程的进程名是包名。
上面在指定OneActivity和TwoActivity的process属性时使用的方法是不一样的。android:process=":remote"这种用“:”的方式是指要在当前的进程名前面附加上当前的包名,这是一种简写的方式; android:process="com.ipc_demo2.remote"这种是完整的命名方式,不会附加包名信息。另外需要注意的是“:”这种方式开启的进程属于当前应用的私有进程,其他应用组件不可以和它跑在同一个进程中,而不用“:”开启的进程属于全局进程,其他应用通过ShareUID方式可以和它跑在同一个进程中。
我们看下日志,会更清晰:
图片1.png
获取进程id和进程名
/**
* 获取进程信息
*/
private void getProcessInfo() {
// 获取活动管理器
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
// 获取正在运行的进程信息
List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
// 遍历所有 进程
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
// 进程名字 一般和包名一样
String processName = runningAppProcessInfo.processName;
// 进程的id
int pid = runningAppProcessInfo.pid;
Log.e("进程间通信", "IpcEntryActivity processName: " + processName + " pid: " + pid);
}
}
通过ShareUID实现两个APP之间的通信
通过ShareUID实现两个APP之间通信最基本的要求就是两个APP的ShareUID相同。
如何设置ShareUID?
图片二.png
以共享res文件为例来进行说明
/**
* 获取其他app的res资源并且显示--以图片为例
*/
private void showOtherAppImage() {
try {
//通过包名获取其他应用的context对象
Context packageContext = createPackageContext("com.example.jinghuang.demo2020", Context.CONTEXT_IGNORE_SECURITY);
if (packageContext != null) {
//获取其他应用的Resource对象
Resources resources = packageContext.getResources();
//getIdentifier方法的第一个参数是资源名(注意不要带文件后缀),
// 第二个参数是资源类型,如果在drawable文件夹中就传入drawable,如果是mipmap文件夹中就传入mipmap
//第三个参数是包名
int resourceId = resources.getIdentifier("ic_launcher", "mipmap", "com.example.jinghuang.demo2020");
Drawable drawable = resources.getDrawable(resourceId);
imageIV.setBackgroundDrawable(drawable);
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
当然,通过shareUID还可以共享其他的数据资源,例如数据库数据等,再这里就不过多介绍了
多进程模式的运行机制以及问题
我们都知道Android为每一个应用分配了一个独立的虚拟机,或者说为每个进程都分配了一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多个副本。
下面我们来看下多进程之间会有什么问题呢?
1、静态成员和单例模式完全失效
2、线程同步机制失效
因为不是在一块内存了,所以不管是锁对象合适锁全局类都无法保证线程同步,因为不同进程所得不是同一个对象。
3、SharedPreferences的可靠性下降
4、Application会多次被闯将。
当一个组件到一个新的进程中的时候,由于系统要在创建新的进程汇总同事分配独立的虚拟机,所以这个过程其实就是启动一个应用的过程。因此,相当于系统又把这个应用重新启动了一遍,既然重新启动了,那么自然会创建新的Application。其实可以这么理解,运行在同一个进程中的组件属于同一个虚拟机和同一个Application,运行在不同进程中的组件是属于两个不同的虚拟机和Application。