我最近更新到了 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)
}
崩溃报告表明,读取 Parcelable 时会崩溃,因为类的 ifTable 在以下情况下为空:Class.isAssignableFrom()
被调用。从the AOSP https://android.googlesource.com/platform/libcore/+/a8a489492749b845cc2a85d67c664449d7b0b019/libart/src/main/java/java/lang/Class.java#171,我可以看到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)
from androidx.core:core-ktx:1.10.0
代替getParcelable(String, Class)
.
我认为这次事故是由两件事不幸结合造成的。
- AGP 8 默认启用 R8 的完整模式。R8 的完整模式剥离了默认构造函数并执行更积极的优化。 https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md#r8-full-mode
- The new
getParcelable(String, Class)
如果未以特定方式定义 Parcelable,则 API 33 中引入的方法会存在一些错误。此处记录了这一点。 https://issuetracker.google.com/274185314
看起来执行起来很脆弱getParcelable(String, Class)
R8 优化某些代码导致了此崩溃。目前的修复似乎是使用旧的getParcelable(String)
API 33 中的方法。Google 表示他们已经解决了这个问题getParcelable(String, Class)
在 API 34 中。
Update: androidx.core:core-ktx:1.10.0
包含此问题的修复。它包含BundleCompat.getParcelable(Bundle, String, Class)
这只会调用新的getParcelable(Bundle, Class)
在 Android U 及以上版本上运行。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)