avatar

目录
Application中以标准模式启动Activity报错的原因分析

个人博客

http://www.milovetingting.cn

Application中以标准模式启动Activity报错的原因分析

Android中,启动的Activity都会运行在相应的任务栈中。如果直接在Application中以标准模式启动Activity,则会报出以下错误(Android7、Android8除外,后面会分析):

Code
1
2
3
4
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中

java
1
2
3
4
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}

在Application的startActivity方法里,又通过mBase来调用startActivity,而mBase就是ContextImpl。ContextImpl的startActivity方法

java
1
2
3
4
5
@Override
public void startActivity(Intent intent) {
warnIfCallingFromSystemProcess();
startActivity(intent, null);
}

这个方法里调用了另一个重载方法

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//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中的方法

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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中的方法

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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中的方法

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@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。

文章作者: milovetingting
文章链接: http://www.milovetingting.cn/2020/03/11/Android/Application%E4%B8%AD%E4%BB%A5%E6%A0%87%E5%87%86%E6%A8%A1%E5%BC%8F%E5%90%AF%E5%8A%A8Activity%E6%8A%A5%E9%94%99%E7%9A%84%E5%8E%9F%E5%9B%A0%E5%88%86%E6%9E%90/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 milovetingting

评论