个人博客
Application中以标准模式启动Activity报错的原因分析
在Android
中,启动的Activity
都会运行在相应的任务栈中。如果直接在Application
中以标准模式
启动Activity,则会报出以下错误(Android7、Android8除外,后面会分析):
Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
at android.app.ContextImpl.startActivity(ContextImpl.java:912)
at android.app.ContextImpl.startActivity(ContextImpl.java:888)
at android.content.ContextWrapper.startActivity(ContextWrapper.java:379)
错误信息提示需要FLAG_ACTIVITY_NEW_TASK
的Flag.
在Activity中调用getApplication()
或者getApplicationContext()
,最终获取到的都是Application,那么getApplication().startActivity()
或者getApplicationContext().startActivity()
方法都在Application中
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
在Application的startActivity方法里,又通过mBase
来调用startActivity,而mBase就是ContextImpl
。ContextImpl的startActivity方法
@Override
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
startActivity(intent, null);
}
这个方法里调用了另一个重载方法
//Android6
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
Android6中,在这个方法里,看到了前面抛出的异常提示。在这里判断了,如果没有加FLAG_ACTIVITY_NEW_TASK
的Flag,就会抛出异常。
再来看Android7中的方法
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in.
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
可以看到,在Android7中,相对Android6,抛出异常还需要符合其它的几个条件。而从前面Application的startActivity方法来看,Bundle类型的options参数为null,所以这个条件不成立,不会抛出异常。
再来看Android8中的方法
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in.
if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
和Android7一样,也判断了options,由于options为null,因此条件不成立,也不会抛出异常。
再来看下Android9中的方法
@Override
public void startActivity(Intent intent, Bundle options) {
warnIfCallingFromSystemProcess();
// Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
// generally not allowed, except if the caller specifies the task id the activity should
// be launched in. A bug was existed between N and O-MR1 which allowed this to work. We
// maintain this for backwards compatibility.
final int targetSdkVersion = getApplicationInfo().targetSdkVersion;
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
&& (targetSdkVersion < Build.VERSION_CODES.N
|| targetSdkVersion >= Build.VERSION_CODES.P)
&& (options == null
|| ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
throw new AndroidRuntimeException(
"Calling startActivity() from outside of an Activity "
+ " context requires the FLAG_ACTIVITY_NEW_TASK flag."
+ " Is this really what you want?");
}
mMainThread.getInstrumentation().execStartActivity(
getOuterContext(), mMainThread.getApplicationThread(), null,
(Activity) null, intent, -1, options);
}
在Android9中,对于options==null用了||判断,那么ActivityOptions.fromBundle(options).getLaunchTaskId() == -1,条件还是会成立,还是会抛出异常。
可以看到,在Android7和Android8中,可以在Application中直接启动Activity,而不需要增加FLAG_ACTIVITY_NEW_TASK的Flag。