先扔代码,在讨论问题
MainActivity
MyService
ThreeActivity
相信大家已经发现问题了,就是在MyService中的 startActivity(new Intent(this, ThreeActivity.class)); 会报错。但是真的会报错吗?请看下面的效果
三星盖乐世C5效果
vivo Y67A效果发现了吗?Android7.0上这段代码是没有问题的,也就是说,Android7.0版本上是可以在不是设置 FLAG_ACTIVITY_NEW_TASK的。而Android6.0版本上是不行的。那么这到底是不是个bug呢?接下来咱们从源码入手看下到底是什么原因。
我们知道像Service,BroadcastReceiver,Application等都是ContextWrapper的子类,调用startActivity()时会调用ContextWrapper的startActivity()
这个mBase就是ContextImpl.这个ContextImpl是在ActivityThread里赋值的:Activity-->ActivityThread::performLaunchActivity()
Service-->ActivityThread::handleCreateService()
Application-->LoadedApk::makeApplication()
有兴趣的同学自行查看,这里就不讨论了 接下来我们先看下ContextImpl的startActivity()
低版本 Android4.4 api-19(截止到Android6.0)
很简单,就是非Activity的Context启动Activity时如果不给intent设置FLAG_ACTIVITY_NEW_TASK就会报错高版本Android8.0 api-27(Android7.0加入)
跟旧版本的代码相比,这里多了个options的非空判断(options != null),关键就在这里. 由于这里options传的就是null,于是就跳过了这个异常.那么,这里的逻辑是"&&",有一个不成立就算失败,那么我们不设置FLA 这里的注释翻译下是:从Activity外部(Service,BroadcastReceiver,Application等)不设置FLAG_ACTIVITY_NEW_TASK是不能启,可是上面的代码明显没有指定task的id就能成功启动了啊,这应该算Android系统的一个bug吧.(看来谷歌的开发和我们一样,都有迷糊的时候)所以Android7.0和8.0版本应该都有这个bug(由于我这里没有8.0的手机,希望各位有条件的小伙伴测试下这个问题)
后续Android9.0代码已修复(&&options != null 已改为 &&options == null)
参考:作者 十蛋斯坦 《刨根问底Service为什么能启动Activity》