getParcelable() 由于 AGP 8 中的空 ifTable 而崩溃

问题描述 投票:0回答:1

我最近更新到 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)

如果有人知道原因或修复方法,将不胜感激!

android parcelable android-r8 android-gradle-plugin-8.0
1个回答
0
投票

tl;dr 解决方法是使用

BundleCompat.getParcelable(Bundle, String, Class)
中的
androidx.core:core-ktx:1.10.0
而不是
getParcelable(String, Class)
.

我认为这次崩溃是由两件事的不幸组合造成的。

  1. AGP 8 默认启用 R8 的完整模式。 R8 的完整模式剥离默认构造函数并执行更积极的优化。
  2. 如果 Parcelable 没有以特定方式定义,API 33 中引入的新
    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)
功能。

© www.soinside.com 2019 - 2024. All rights reserved.