下面列出了android.content.pm.ActivityInfo#LAUNCH_MULTIPLE 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static void onActivtyDestory(Activity activity) {
synchronized (mRunningActivityList) {
RunningActivityRecord value = mRunningActivityList.remove(activity);
if (value != null) {
ActivityInfo targetActivityInfo = value.targetActivityInfo;
if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
mRunningSingleStandardActivityList.remove(value.index);
} else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
mRunningSingleTopActivityList.remove(value.index);
} else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
mRunningSingleTaskActivityList.remove(value.index);
} else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
mRunningSingleInstanceActivityList.remove(value.index);
}
}
}
}
/**
* 查询插件Activity对应的占位Activity
*
* @param pluginActivity 插件Activity全名,格式为:packageName/activityName
* @return 返回插件Activity与占位Activity。如果pluginActivity是非标准启动模式,pluginActivity还没启动就返回null;
* 如果pluginActivity是标准启动模式,始终返回{@link LaunchModeManager#MODE_STANDARD}
*/
@SuppressWarnings("unused")
@Nullable
public String queryProxyActivity(@NonNull String pluginActivity) {
String proxyActivity = mSingleTaskPool.findProxyActivity(pluginActivity);
if (null == proxyActivity) {
proxyActivity = mSingleInstancePool.findProxyActivity(pluginActivity);
}
if (null == proxyActivity) {
proxyActivity = mSingleTopPool.findProxyActivity(pluginActivity);
}
//标准启动模式
if (null == proxyActivity) {
String[] componentItems = pluginActivity.split("/");
if (componentItems.length != 2) {
return null;
}
ActivityInfo info = PhantomCore.getInstance()
.findActivityInfo(new ComponentName(componentItems[0], componentItems[1]));
if (null == info) {
return null;
}
if (info.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
proxyActivity = MODE_STANDARD;
}
}
return proxyActivity;
}
/** Unbind the stub activity from real activity */
private void inqueueStubActivity(ActivityInfo ai, String realActivityClazz) {
if (ai.launchMode == ActivityInfo.LAUNCH_MULTIPLE) return;
if (mStubQueue == null) return;
int countForMode = STUB_ACTIVITIES_COUNT;
int offset = (ai.launchMode - 1) * countForMode;
for (int i = 0; i < countForMode; i++) {
String stubClazz = mStubQueue[i + offset];
if (stubClazz != null && stubClazz.equals(realActivityClazz)) {
mStubQueue[i + offset] = null;
break;
}
}
}
public static String getLaunchMode(int mode) {
switch (mode) {
case ActivityInfo.LAUNCH_MULTIPLE:
return "Multiple";
case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
return "Single instance";
case ActivityInfo.LAUNCH_SINGLE_TASK:
return "Single task";
case ActivityInfo.LAUNCH_SINGLE_TOP:
return "Single top";
default:
return "null";
}
}
public static void onActivtyCreate(Activity activity, ActivityInfo targetActivityInfo, ActivityInfo stubActivityInfo) {
synchronized (mRunningActivityList) {
RunningActivityRecord value = new RunningActivityRecord(activity, targetActivityInfo, stubActivityInfo, findMaxIndex() + 1);
mRunningActivityList.put(activity, value);
if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
mRunningSingleStandardActivityList.put(value.index, value);
} else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
mRunningSingleTopActivityList.put(value.index, value);
} else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
mRunningSingleTaskActivityList.put(value.index, value);
} else if (targetActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
mRunningSingleInstanceActivityList.put(value.index, value);
}
}
}
public static void beforeStartActivity() {
synchronized (mRunningActivityList) {
for (RunningActivityRecord record : mRunningActivityList.values()) {
if (record.stubActivityInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
continue;
} else if (record.stubActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
doFinshIt(mRunningSingleTopActivityList);
} else if (record.stubActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
doFinshIt(mRunningSingleTopActivityList);
} else if (record.stubActivityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
doFinshIt(mRunningSingleTopActivityList);
}
}
}
}
/**
* Perform clear operation as requested by
* {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
* stack to the given task, then look for
* an instance of that activity in the stack and, if found, finish all
* activities on top of it and return the instance.
*
* @param newR Description of the new activity being started.
* @return Returns the old activity that should be continued to be used,
* or null if none was found.
*/
final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
int numActivities = mActivities.size();
for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = mActivities.get(activityNdx);
if (r.finishing) {
continue;
}
if (r.realActivity.equals(newR.realActivity)) {
// Here it is! Now finish everything in front...
final ActivityRecord ret = r;
for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
r = mActivities.get(activityNdx);
if (r.finishing) {
continue;
}
ActivityOptions opts = r.takeOptionsLocked();
if (opts != null) {
ret.updateOptionsLocked(opts);
}
if (mStack != null && mStack.finishActivityLocked(
r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
--activityNdx;
--numActivities;
}
}
// Finally, if this is a normal launch mode (that is, not
// expecting onNewIntent()), then we will finish the current
// instance of the activity so a new fresh one can be started.
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
&& (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
&& !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
if (!ret.finishing) {
if (mStack != null) {
mStack.finishActivityLocked(
ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
}
return null;
}
}
return ret;
}
}
return null;
}
/**
* 获取一个占位activity
*
* @param pluginActivity 插件activity
* @param launchMode 插件activity启动模式
* @param isFixed 是否建立固定映射关系
* @return 占位activity
* @throws ProxyActivityLessException 占位activity不够异常
*/
private String findActivity(String pluginActivity, int launchMode, boolean isFixed)
throws ProxyActivityLessException {
String activity = MODE_STANDARD;
ActivityPool pool = null;
switch (launchMode) {
case ActivityInfo.LAUNCH_MULTIPLE:
final PhantomCore phantomCore = PhantomCore.getInstance();
final ComponentName componentName = ComponentName.unflattenFromString(pluginActivity);
if (componentName != null) {
final ActivityInfo ai = phantomCore.findActivityInfo(componentName);
final PluginInfo pluginInfo = phantomCore.findPluginInfoByActivityName(componentName);
final int themeResourceId = ai == null ? -1 : ai.getThemeResource();
if (themeResourceId != -1 && pluginInfo != null) {
final Resources resources = pluginInfo.getPluginResources();
if (resources != null) {
final Resources.Theme theme = resources.newTheme();
theme.applyStyle(themeResourceId, true);
final TypedArray sa = theme.obtainStyledAttributes(
new int[]{android.R.attr.windowIsTranslucent});
final boolean translucent = sa.getBoolean(0, false);
sa.recycle();
activity = translucent ? MODE_STANDARD_TRANSLUCENT : MODE_STANDARD;
}
}
}
break;
case ActivityInfo.LAUNCH_SINGLE_TOP:
pool = mSingleTopPool;
break;
case ActivityInfo.LAUNCH_SINGLE_INSTANCE:
pool = mSingleInstancePool;
break;
case ActivityInfo.LAUNCH_SINGLE_TASK:
pool = mSingleTaskPool;
break;
default:
break;
}
if (null != pool) {
activity = isFixed ? pool.resolveFixedActivity(pluginActivity) : pool.resolveActivity(pluginActivity);
}
String msg = String.format("resolve %s Activity for %s proxy is %s, fixed is %s",
launchModeToString(launchMode), pluginActivity, activity, isFixed);
VLog.d(msg);
if (null == activity) {
//占位activity不够使用, 这种情况不做处理,宿主提供足够的占位activity
//这里不做主动回收,如果做主动回收可能会使程序正常执行流程发送改变
ProxyActivityLessException pae = new ProxyActivityLessException(msg);
LogReporter.reportException(pae, null);
mCache.clean();
throw pae;
}
return activity;
}
/** Get an usable stub activity clazz from real activity */
private String dequeueStubActivity(ActivityInfo ai, String realActivityClazz) {
if (ai.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
// In standard mode, the stub activity is reusable.
// Cause the `windowIsTranslucent' attribute cannot be dynamically set,
// We should choose the STUB activity with translucent or not here.
Resources.Theme theme = Small.getContext().getResources().newTheme();
theme.applyStyle(ai.getThemeResource(), true);
TypedArray sa = theme.obtainStyledAttributes(
new int[] { android.R.attr.windowIsTranslucent });
boolean translucent = sa.getBoolean(0, false);
sa.recycle();
return translucent ? STUB_ACTIVITY_TRANSLUCENT : STUB_ACTIVITY_PREFIX;
}
int availableId = -1;
int stubId = -1;
int countForMode = STUB_ACTIVITIES_COUNT;
int countForAll = countForMode * 3; // 3=[singleTop, singleTask, singleInstance]
if (mStubQueue == null) {
// Lazy init
mStubQueue = new String[countForAll];
}
int offset = (ai.launchMode - 1) * countForMode;
for (int i = 0; i < countForMode; i++) {
String usedActivityClazz = mStubQueue[i + offset];
if (usedActivityClazz == null) {
if (availableId == -1) availableId = i;
} else if (usedActivityClazz.equals(realActivityClazz)) {
stubId = i;
}
}
if (stubId != -1) {
availableId = stubId;
} else if (availableId != -1) {
mStubQueue[availableId + offset] = realActivityClazz;
} else {
// TODO:
Log.e(TAG, "Launch mode " + ai.launchMode + " is full");
}
return STUB_ACTIVITY_PREFIX + ai.launchMode + availableId;
}
private static void loadStubActivity() {
Intent launchModeIntent = new Intent();
launchModeIntent.setAction(buildDefaultAction());
launchModeIntent.setPackage(FairyGlobal.getHostApplication().getPackageName());
List<ResolveInfo> list = FairyGlobal.getHostApplication().getPackageManager().queryIntentActivities(launchModeIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (list != null && list.size() >0) {
for (ResolveInfo resolveInfo:
list) {
if (resolveInfo.activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
singleTaskActivityMapping.put(resolveInfo.activityInfo.name, null);
} else if (resolveInfo.activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
singleTopActivityMapping.put(resolveInfo.activityInfo.name, null);
} else if (resolveInfo.activityInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
singleInstanceActivityMapping.put(resolveInfo.activityInfo.name, null);
} else if (resolveInfo.activityInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
if (resolveInfo.activityInfo.theme == android.R.style.Theme_Translucent) {
standardActivityTranslucentMapping.put(resolveInfo.activityInfo.name, null);
} else if (resolveInfo.activityInfo.screenOrientation == SCREEN_ORIENTATION_LANDSCAPE) {
standardLandspaceActivity = resolveInfo.activityInfo.name;
} else {
standardActivityMapping.put(resolveInfo.activityInfo.name, null);
}
}
}
}
}