resolveActivity是Activity创建过程中非常重要的一个函数,会在ActivityStack
的startActivityMayWait
中调用。这个函数的主要作用就是根据intent去收集需要启动的activity的信息,看下函数的原型:
ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug,
String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
// Collect information about the target of the Intent.
ActivityInfo aInfo;
try {
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveIntent(
intent, resolvedType,
PackageManager.MATCH_DEFAULT_ONLY
| ActivityManagerService.STOCK_PM_FLAGS);
aInfo = rInfo != null ? rInfo.activityInfo : null;
} catch (RemoteException e) {
aInfo = null;
}
if (aInfo != null) {
// Store the found target back into the intent, because now that
// we have it we never want to do this again. For example, if the
// user navigates back to this point in the history, we should
// always restart the exact same activity.
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
// Don't debug things in the system process
if (debug) {
if (!aInfo.processName.equals("system")) {
mService.setDebugApp(aInfo.processName, true, false);
}
}
if (profileFile != null) {
if (!aInfo.processName.equals("system")) {
mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
profileFile, profileFd, autoStopProfiler);
}
}
}
return aInfo;
}
为了不影响对resolveActivity
的分析,需要把Activity启动过程中传到此函数的参数说明一下,当我们点击launcher界面启动一个Activity的时候,intent就是我们正常启动启动Activity时的intent;其余的boolean类型的值为false,非boolean类型的值为null。
函数的关键在AppGlobals.getPackageManager().resolveIntent(intent, resolvedType, PackageManager.MATCH_DEFAULT_ONLY | ActivityManagerService.STOCK_PM_FLAGS)
。AppGlobals这个变量提供了一个静态方法,方便应用可以获取系统的函数调用接口。最重要的部分应该就是getPackageManager().resolveInten
了,ok,到PackageManagerService看下resolveIntent这个方法。
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags) {
List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags);
return chooseBestActivity(intent, resolvedType, flags, query);
}
resolveIntent经过了两个步骤,首先根据传递的信息选出符合条件的集合,然后从集合中找出最合适的信息。第一步queryIntentActivities
根据intent, resolveType,flag信息选出可能存在的Activity的信息;chooseBestActivity
会从第一步的信息的集合中选择最符合条件的Activity,如果chooseBestActivity
选出的符合条件的Activity不止一个,则会让用户选择具体需要启动哪个Activity。可以看下chooseBestActivity
的实现:
private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query) {
if (query != null) {
final int N = query.size();
/**如果根据条件只找到了一个Activity,则直接返回*/
if (N == 1) {
return query.get(0);
} else if (N > 1) {
/**根据条件找到了多个Activity*/
// If there is more than one activity with the same priority,
// then let the user decide between them.
ResolveInfo r0 = query.get(0);
ResolveInfo r1 = query.get(1);
if (DEBUG_INTENT_MATCHING) {
Log.d(TAG, r0.activityInfo.name + "=" + r0.priority + " vs "
+ r1.activityInfo.name + "=" + r1.priority);
}
/**如果第一个Activity有更高的优先级,或者default设置不相同,则返回第一个Activity*/
// If the first activity has a higher priority, or a different
// default, then it is always desireable to pick it.
if (r0.priority != r1.priority
|| r0.preferredOrder != r1.preferredOrder
|| r0.isDefault != r1.isDefault) {
return query.get(0);
}
// If we have saved a preference for a preferred activity for
// this Intent, use that.
ResolveInfo ri = findPreferredActivity(intent, resolvedType,
flags, query, r0.priority);
if (ri != null) {
return ri;
}
return mResolveInfo;
}
}
return null;
}
多有多个Activity符合查询条件时,最终会进入findPreferredActivity
找到最合适的Activity。findPreferredActivity
最终会调用findPersistentPreferredActivityLP
这个函数。 由于正在分析Activity的启动流程,这个函数我还没有去分析,个人猜想可能是这样一个流程,类似于我们在android上打开一个网页,如果你有多个浏览器可以去打开网页,那么android弹出对话框,让用户选择使用哪个浏览器去打开网页;如果用户选择了一个浏览器并且勾选了总是
,那么下次再打开网页的时候就会启动已经默认的浏览器,如果用户没有勾选总是
,则每次打开网页的时候就会弹出对话框让用户选择。