有以下代码,在一个Service中启动Activity,启动Activity必不可少的就是Context对象,Service和Activity都是Context。使用Activity类型的Context是可以启动一个新的Activity的,但使用Service类型的Context启动Activity时,需要在Intent中手动添加一个 FLAG_ACTIVITY_NEW_TASK 才能正确启动Activity。

internal class XxxIntentService : BaseJobIntentService() {
  override fun onHandleWork(intent: Intent) {
    // getApplicationContext()
    goXxxActivity(applicationContext, url)
  }
}

// 跳转到某个Activity
fun goXxxActivity(context: Context, url: String) {
    val intent = Intent(context, XxxActivity::class.java)
    intent.putExtra(XxxActivity.EXTRA_URL, url)
    ActivityCompat.startActivity(context, intent, null)
}

运行以上代码,Android O 版本中,能正常跳转到新的Activity,但是在Android P 版本中,系统会抛出异常:

android.util.AndroidRuntimeException: 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)
    at com.example.test.XxxIntentService$1.onHandleWork(XxxIntentService.java:19)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Android O 版本上,和文章开头所说的观点不同,即使Intent没有设置FLAG_ACTIVITY_NEW_TASK,新的Activity仍然能被启动起来,但是在Android P 版本中,则和文章开头所说的观点相同。为什么?

1.1. P vs O

既然P版本会报错,O版本不报错,那对比一下P版本和O版本,在启动Activity时,都做了哪些检验。

1.1.1. Android P

P

在O版本是,抛异常的检验条件是:

(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)

从上面的注释可以看出,在N版本到O-MR1版本之间,Android系统源码本身存在一个Bug,导致在Service中,即使没有设置FLAG_ACTIVITY_NEW_TASK,也能启动一个Activity。

http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/app/ContextImpl.java#886

结合文章开头的Service中启动Activity的代码,我们传的options为空,所以在P版本中,检验条件为true,则会正常抛出异常。

1.1.2. Android N - O

O

在O版本是,抛异常的检验条件是:

(intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 &&
(options != null && ActivityOptions.fromBundle(options).getLaunchTaskId() == -1))

http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/app/ContextImpl.java#794

结合文章开头的Service中启动Activity的代码,我们传的options为空,所以在O版本中,检验条件为false,自然不会抛出异常。

1.1.3. Android M

M

在O版本是,抛异常的检验条件是:

(intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0)

http://androidxref.com/6.0.1_r10/xref/frameworks/base/core/java/android/app/ContextImpl.java#669

结合文章开头的Service中启动Activity的代码,在M及以前的版本,没有设置FLAG_ACTIVITY_NEW_TASK,检验条件为true,会抛出异常。

更多:

Activity堆栈管理

results matching ""

    No results matching ""