通过启动Activity来理解Intent+Bundle跨进程
Posted zhangjin1120
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过启动Activity来理解Intent+Bundle跨进程相关的知识,希望对你有一定的参考价值。
目录
从Intent+Bundle到Binder
进程间通信为什么叫IPC?
IPC是Inter-Process Communication 的缩写,意为进程间通讯或跨进程通信,指两个进程之间进行数据交换的过程。
Intent与Bundle之间的关系是什么?
Intent可以携带Bundle类型的对象,然后作为参数传递给AMS,AMS负责启动另外一个Activity或者其他组件。
//Intent.java源码
public Intent putExtras(Bundle extras)
if (mExtras == null)
mExtras = new Bundle();
mExtras.putAll(extras);
return this;
怎么用Intent启动另外一个App的Activity?
方式有几种,详细参考:Android在一个应用程序中启动另一个应用程序。
下面其中一种,根据应用的包名,启动它的Activity。可以看到Intent作为参数,最终执行了startActivity(intent);
。
private void openApp(String packageName)
PackageInfo pi = getPackageManager().getPackageInfo(packageName, 0);
Intent resolveIntent = new Intent(Intent.ACTION_MAIN, null);
resolveIntent.addCategory(Intent.CATEGORY_LAUNCHER);
resolveIntent.setPackage(pi.packageName);
List<ResolveInfo> apps = pm.queryIntentActivities(resolveIntent, 0);
ResolveInfo ri = apps.iterator().next();
if (ri != null)
String packageName = ri.activityInfo.packageName;
String className = ri.activityInfo.name;
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ComponentName cn = new ComponentName(packageName, className);
intent.setComponent(cn);
startActivity(intent);
在startActivity(intent);
中,Intent到底传递给了谁?
ActivityManagerService
整个startActivity()的过程,这篇文章:【Android源码】Intent 源码分析 已经分析的很清楚了,我把跨进程通信相关的部分贴出来。从下面的代码可以看出来intent传递给了ActivityManagerNative.getDefault().startActivity();
,而ActivityManagerNative是ActivityManagerService的父类,这个后面的问题会介绍。
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options)
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
try
// 将Intent数据添加到剪切板上
intent.migrateExtraStreamToClipData();
// 准备离开当前进程
intent.prepareToLeaveProcess(who);
// 调用ActivityManagerService的startActivity方法
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
// 检查并回调给调用者
checkStartActivityResult(result, intent);
catch (RemoteException e)
throw new RuntimeException("Failure from system", e);
return null;
启动另一个进程的Activity和AMS有什么关系?为什么要把Intent传递给AMS?
Activity 启动过程是由 ActivityMangerService(AMS) 来启动的,底层原理是 Binder实现的,最终交给 ActivityThread 的 performActivity 方法来启动它。
Binder和AMS是什么关系?
AMS是一个Binder的子类。 AMS继承了ActivityManagerNative,ActivityManagerNative又继承了Binder,所以ActivityManagerService本身就是一个Binder,可以用于进程间通信。
可以得出结论:Intent+Bundle实现跨进程通信,本质还是Binder机制。
AMS属于哪个进程?
System_server进程
启动另一个App的Activity,还需要IPC吗?
现代化操作系统通常具备两种处理器模式:用户模式(User Mode)与内核模式(Kernel Mode)。操作系统(或指操作系统内核)位于内核模式,可管理计算机的全部资源,而处于用户模式的用户进程若需要执行如访问磁盘等特权操作,就需要通过系统调用(System Call)交由内核模式的操作系统执行。
原因很简单,银行是不会让取款的客户进金库自己数钱的。
android 底层的 Linux Kernel 自然采用了这一权限机制,内核与相关服务运行的内存空间称为内核空间(Kernel Space),而用户进程所运行的内存空间称为用户空间(User Space)。当用户进程通过系统调用进行特权操作时,称此时进程为内核态(Kernel Mode,需注意根据上下文与内核模式进行区分)与用户态(User Mode)。
ActivityManagerService是系统的引导服务,应用进程的启动、切换和调度、四大组件的启动和管理都需要AMS的支持。AMS属于system_server进程,应用进程要和AMS通信,就需要跨进程。
Activity的启动需要做哪些工作?
应用A启动应用B的Activity,属于应用程序的启动或者调度,又AMS负责。下图是Lancher启动某个应用的图解,可以辅助理解应用A启动应用B的Activity的流程。
为什么跨进程通信需要序列化?
android不同的进程都有自己独立的内存空间,且相互之间不能进行访问。如果像我们平常传一个句柄的方式去传值的话肯定是失败的,因为句柄也是指定内存空间的一个区域。现在进程无法访问目标进程的内存空间,所以句柄传过去也是没有用的。
所以我们必须将要传输的数据转换成能够在内存空间流通的形式。这个转化过程就叫做序列化和反序列化。 简单来说是这样的:比如现在我们要将一个对象的数据从客户端传到服务端去,我们就可以在客户端对这个对象进行序列化的操作,将其中包含的数据转化为序列化流,然后将这个序列化流传输到服务端的内存中去,再在服务端对这个数据流进行反序列化的操作,从而还原其中包含的数据。
以上是关于通过启动Activity来理解Intent+Bundle跨进程的主要内容,如果未能解决你的问题,请参考以下文章
Android12.2 利用Intent启动和关闭Activity
Android-----Intent中通过startActivity(Intent intent )显式启动新的Activity