在Android中,我们经常需要使用到Intent类,它用于跳转Activity、启动Service、发布广播等功能,它是系统各组件之间的纽带,也可以通过Intent传递数据,因为有Intent才使得Android的组件耦合度降低。
原型模式
首先我们跳转到Intent.java:
public class Intent implements Parcelable, Cloneable {
}
我们可以发现Intent实现了Cloneable接口,所以我们可以得出一个结论,Intent使用了原型设计模式,(原型设计模式介绍参考:点击此处)我们搜索clone()方法:
@Override
public Object clone() {
return new Intent(this);
}
public Intent(Intent o) {
this.mAction = o.mAction;
this.mData = o.mData;
this.mType = o.mType;
this.mPackage = o.mPackage;
this.mComponent = o.mComponent;
this.mFlags = o.mFlags;
this.mContentUserHint = o.mContentUserHint;
if (o.mCategories != null) {
this.mCategories = new ArraySet<String>(o.mCategories);
}
if (o.mExtras != null) {
this.mExtras = new Bundle(o.mExtras);
}
if (o.mSourceBounds != null) {
this.mSourceBounds = new Rect(o.mSourceBounds);
}
if (o.mSelector != null) {
this.mSelector = new Intent(o.mSelector);
}
if (o.mClipData != null) {
this.mClipData = new ClipData(o.mClipData);
}
}
Intent如何工作
Intent在使用的时候,可以通过添加flag、category还有需要跳转的对象等来实现功能,那么Intent是如何通过查找并匹配所需要跳转的Activity呢?
-
app信息表的构建
-
匹配
当app信息表被构建好之后,Intent就可以通过信息表来匹配。
我们以启动某个具体的Activity来分析,首先我们启动的代码是这样的:
// 显式Intent Intent intent = new Intent(this, SecondActivity.class); startActivity(intent); // 隐式Intent Intent intent = new Intent(Intent.ACTION_SENDTO); startActivity(intent);
startActivity方法,通过一系列的调用:
@Override public void startActivity(Intent intent) { this.startActivity(intent, null); } @Override public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. startActivityForResult(intent, -1); } } public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { // 启动Activity Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); // 发送启动请求 if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } cancelInputsAndStartExitTransition(options); } else { } }
最终调用的是startActivityForResult方法,在这个方法中直接调用execStartActivity方法启动Activity:
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; }
execStartActivity方法里面其实就是调用了ActivityManagerService的startActivity方法:
final int startActivity(Intent intent, ActivityStackSupervisor.ActivityContainer container) { enforceNotIsolatedCaller("ActivityContainer.startActivity"); final int userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), mStackSupervisor.mCurrentUser, false, ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null); // TODO: Switch to user app stacks here. String mimeType = intent.getType(); final Uri data = intent.getData(); if (mimeType == null && data != null && "content".equals(data.getScheme())) { mimeType = getProviderMimeType(data, userId); } container.checkEmbeddedAllowedInner(userId, intent, mimeType); intent.addFlags(FORCE_NEW_TASK_FLAGS); return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null, 0, 0, null, null, null, null, false, userId, container, null); }
这个方法会调用ActivityStarter的startActivityMayWait方法,这个方法中又会调用ActivityStackSupervisor.resolveIntent方法,而这个方法就是调用的PMS的resolveIntent方法:
// ActivityStackSupervisor.java ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) { try { return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType, PackageManager.MATCH_DEFAULT_ONLY | flags | ActivityManagerService.STOCK_PM_FLAGS, userId); } catch (RemoteException e) { } return null; } // PackageManagerService.java @Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent"); if (!sUserManager.exists(userId)) return null; flags = updateFlagsForResolve(flags, userId, intent); enforceCrossUserPermission(Binder.getCallingUid(), userId, false /*requireFullPermission*/, false /*checkShell*/, "resolve intent"); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities"); // 获取列表 final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); // 通过列表选择出最合适的info对象 final ResolveInfo bestChoice = chooseBestActivity(intent, resolvedType, flags, query, userId); if (isEphemeralAllowed(intent, query, userId)) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral"); final EphemeralResolveInfo ai = getEphemeralResolveInfo(intent, resolvedType, userId); if (ai != null) { if (DEBUG_EPHEMERAL) { Slog.v(TAG, "Returning an EphemeralResolveInfo"); } bestChoice.ephemeralInstaller = mEphemeralInstallerInfo; bestChoice.ephemeralResolveInfo = ai; } Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } return bestChoice; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } }
queryIntentActivitiesInternal方法返回的结果就是符合intent的ActivityInfo列表:
private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType, int flags, int userId) { // 获取Intent的Component对象 ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } // 不为空,是显式Intent,直接获取到ActivityInfo返回 if (comp != null) { final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); final ActivityInfo ai = getActivityInfo(comp, flags, userId); if (ai != null) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; list.add(ri); } return list; } // 为空,是隐式Intent synchronized (mPackages) { final String pkgName = intent.getPackage(); if (pkgName == null) { // 代码省略 return result; } // 通过包名获取到Package对象 final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { // 在获取到ActivityInfo对象 return filterIfNotSystemUser( mActivities.queryIntentForPackage( intent, resolvedType, flags, pkg.activities, userId), userId); } return new ArrayList<ResolveInfo>(); } }
上面这个方法就是Intent获取到ActivityInfo的核心,它的大致过程如下:
- 首先获取Intent的Component对象,如果不为空,说明指定了Componet,那么就直接通过Componet找到ActivityInfo列表,并且这个列表size为1,所以这个ActivityInfo就是指定需要跳转的组件。
- 如果没有指定Component,那就是隐式Intent调用,接着获取Intent传递的需要跳转的包名。
- 如果包名为空,则会通过ActivityIntentResolver等进行模糊匹配,比如根据Action、Category等。
- 如果包名不为空,则直接根据包名来获取到对应的ActivityInfo对象,而mActivities就是PMS存储的activity信息表。
网友评论