我最近更新到 AGP 8,并发布了 play 商店的更新。我收到有关最近未更改的代码区域发生一些崩溃的报告。我相当有信心这是由 AGP 8 升级引起的崩溃,特别是围绕 R8 全模式。
围绕崩溃的代码正在恢复布局管理器的状态。
恢复码
if (savedInstanceState != null) {
oldRecyclerLayoutState = savedInstanceState.getParcelableCompat(
SIS_RECYCLER_LAYOUT_STATE,
)
}
保存实例代码
private lateinit var layoutManager: LinearLayoutManager
...
override fun onSaveInstanceState(outState: Bundle) {
outState.putParcelable(SIS_RECYCLER_LAYOUT_STATE, layoutManager.onSaveInstanceState())
super.onSaveInstanceState(outState)
}
崩溃报告表明,当调用
Class.isAssignableFrom()
时,由于类的 ifTable 为空,读取 parcelable 会崩溃。从AOSP,我可以看到一个ifTable
是一个接口表。我假设 isAssignableFrom
正在使用 ifTable
来确定可分配性但是由于类为空而无法读取它。不幸的是,错误并没有告诉我哪个类是空的。
完整的堆栈跟踪:
Fatal Exception: java.lang.NullPointerException: Attempt to read from field 'java.lang.Object[] java.lang.Class.ifTable' on a null object reference in method 'boolean java.lang.Class.isAssignableFrom(java.lang.Class)'
at java.lang.Class.isAssignableFrom(Class.java:579)
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:4865)
at android.os.Parcel.readParcelableInternal(Parcel.java:4778)
at android.os.Parcel.readValue(Parcel.java:4544)
at android.os.Parcel.readValue(Parcel.java:4324)
at android.os.Parcel.-$$Nest$mreadValue()
at android.os.Parcel$LazyValue.apply(Parcel.java:4422)
at android.os.Parcel$LazyValue.apply(Parcel.java:4381)
at android.os.BaseBundle.getValueAt(BaseBundle.java:394)
at android.os.BaseBundle.getValue(BaseBundle.java:374)
at android.os.BaseBundle.getValue(BaseBundle.java:357)
at android.os.BaseBundle.get(BaseBundle.java:696)
at android.os.Bundle.getParcelable(Bundle.java:947)
at com.ggstudios.lolcatalyst.util.ext.BundleExtKt.getParcelableCompat(BundleExt.kt:21)
at com.ggstudios.lolcatalyst.summonerlookup.SummonerProfileFragment.onViewCreated(SummonerProfileFragment.kt:422)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3137)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1435)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2979)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:2890)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3138)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:552)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1435)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2979)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2897)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:351)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:251)
at com.ggstudios.lolcatalyst.activity.abs.BaseActivity.onStart(BaseActivity.kt:90)
at com.ggstudios.lolcatalyst.activity.MainActivity.onStart(MainActivity.kt)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1510)
at android.app.Activity.performStart(Activity.java:8603)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4191)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2571)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8741)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
如果有人知道原因或修复方法,将不胜感激!
tl;dr 解决方法是使用
BundleCompat.getParcelable(Bundle, String, Class)
中的 androidx.core:core-ktx:1.10.0
而不是 getParcelable(String, Class)
.
我认为这次崩溃是由两件事的不幸组合造成的。
getParcelable(String, Class)
方法有一些错误。 这在此处记录。看起来
getParcelable(String, Class)
的脆弱实现和优化某些代码的 R8 导致了这次崩溃。现在的修复似乎是使用 API 33 中的旧 getParcelable(String)
方法。谷歌表示他们已经修复了 API 34 中的getParcelable(String, Class)
问题。
更新:
androidx.core:core-ktx:1.10.0
包含针对此问题的修复程序。它包含BundleCompat.getParcelable(Bundle, String, Class)
,只会在Android U及更高版本上调用新的getParcelable(Bundle, Class)
功能。