Android 8.0 上一个奇怪的IllegalStateException

Android 8.0 上一个奇怪的IllegalStateException

前言

API 26之后,给Activity应用Dialog主题,大部分第三方ROM都存在巨坑。

起因

公司项目在适配Android 8.0之后,爆发了一个触发率极高,而在Google Play Console上又找不到任何有效错误信息的IllegalStateException。Google Play Console统计信息如下:

java.lang.RuntimeException:
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3184)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3279)
  at android.app.ActivityThread.-wrap12 (Unknown Source)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1881)
  at android.os.Handler.dispatchMessage (Handler.java:108)
  at android.os.Looper.loop (Looper.java:166)
  at android.app.ActivityThread.main (ActivityThread.java:7406)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:245)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:926)
Caused by: java.lang.IllegalStateException:
  at android.app.Activity.onCreate (Activity.java:1076)
  at android.support.v4.app.SupportActivity.onCreate (SupportActivity.java)
  at android.support.v4.app.FragmentActivity.onCreate (FragmentActivity.java:15)
  at android.support.v7.app.AppCompatActivity.onCreate (AppCompatActivity.java:36)
  at android.app.Activity.performCreate (Activity.java:7365)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1218)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3137)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3279)
  at android.app.ActivityThread.-wrap12 (Unknown Source)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1881)
  at android.os.Handler.dispatchMessage (Handler.java:108)
  at android.os.Looper.loop (Looper.java:166)
  at android.app.ActivityThread.main (ActivityThread.java:7406)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:245)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:926)

以及统计到的另一个错误信息:

java.lang.RuntimeException:
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2946)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3046)
  at android.app.ActivityThread.-wrap11 (Unknown Source)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1688)
  at android.os.Handler.dispatchMessage (Handler.java:105)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6809)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:240)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:767)
Caused by: java.lang.IllegalStateException:
  at android.app.Activity.onCreate (Activity.java:995)
  at android.support.v4.app.SupportActivity.onCreate (SupportActivity.java)
  at android.support.v4.app.FragmentActivity.onCreate (FragmentActivity.java:15)
  at android.support.v7.app.AppCompatActivity.onCreate (AppCompatActivity.java:36)
  at android.app.Activity.performCreate (Activity.java:6998)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1230)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2899)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3046)
  at android.app.ActivityThread.-wrap11 (Unknown Source)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1688)
  at android.os.Handler.dispatchMessage (Handler.java:105)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6809)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:240)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:767)

两份错误信息并无太大区别,但就从错误信息来看,触发该Bug的必然是项目中的Activity,而该Activity在执行其父类的代码时就已经崩溃,而自身的代码并没有执行。这找起来就棘手了,都不清楚是哪个页面引发的。于是再结合错误信息截图来看看:

《Android 8.0 上一个奇怪的IllegalStateException》 2018-03-16-1.PNG
《Android 8.0 上一个奇怪的IllegalStateException》 2018-03-16-2.PNG

错误仅仅发生在适配API 26的版本上,错误仅仅发生在API 26的ROM,而手头的两台设备,Nexus 5X 跟Pixel 2 XL都未触发,而Google Play Console上也没有统计到亲儿子存在该问题,出问题的基本上都是国内的ROM,尤其华为的居多。

现在所知的关键点是,targetSdkVersion在26及以上且系统API在26及以上的设备才会触发,而触发的Activity连自身的代码都没有执行。那么就只剩Activity的声明处了,先去8.0行为变更里面看了一遍,并没有对Activity声明增加新的要求。翻开AndroidManifest.xml文件,所有的Activity都检查一遍,也并没有不和谐之处,无非是设置一下label以及配置一下theme。这些信息都不足以查出触发点来时,就只能找一台可以触发的机器了,于是通过测试的同事找来一台在触发机器列表里的手机,然而系统与应用及设备均符合触发条件,可这台机器就是不触发,实在无解。

眼见着就要无从下手了,但忽然想到公司项目还接入了友盟统计,抱着侥幸的心理上去看看是否有什么蛛丝马迹。不常使用友盟查看崩溃统计主要是其C++层的报错完全统计不到(项目涉及NDK开发)而数据又不够直观。幸运的是友盟果然统计到了重要信息,除开上面的报错信息以外,其补上了Google Play Console漏掉的一部分,而这一部分非常关键:

java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
  at android.app.Activity.onCreate (Activity.java:1076)
  at android.support.v4.app.SupportActivity.onCreate (SupportActivity.java)
  at android.support.v4.app.FragmentActivity.onCreate (FragmentActivity.java:15)
  at android.support.v7.app.AppCompatActivity.onCreate (AppCompatActivity.java:36)
  at android.app.Activity.performCreate (Activity.java:7365)
  at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1218)
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:3137)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:3279)
  at android.app.ActivityThread.-wrap12 (Unknown Source)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1881)
  at android.os.Handler.dispatchMessage (Handler.java:108)
  at android.os.Looper.loop (Looper.java:166)
  at android.app.ActivityThread.main (ActivityThread.java:7406)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:245)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:926)

问题

其实仅仅这一句话最关键:

Only fullscreen opaque activities can request orientation

只有全屏不透明的Activity可以请求方向

没错,项目里的部分Activity应用了Dialog的主题,也就是说它是非全屏且透明的Activity。然而奇怪的是,这些Dialog样式的Activity并没有设定screenOrientation属性,也就是该属性用的是默认值,于该Activity来说并没有request orientation,因此,此处个人判定,应该是第三方ROM的问题。对于Dialog样式的Activity,即便是设置了screenOrientation属性,也不应该Activity崩溃,而应该是设置的screenOrientation属性无效,更何况并没有设置screenOrientation属性,仅仅是对Activity应用了Dialog的主题。

解决

定义一个透明的Activity主题:增加android:windowIsTranslucent属性为true,并设置透明的背景。而对于非要使用对话框样式的Activity,那么就对照对话框的Theme进行设置了,此处不展开说了。

    原文作者:AlexMofer
    原文地址: https://www.jianshu.com/p/a80c6d753b6b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞