我使用默认为 1 的 ViewPager 和 FragmentStatePagerAdapter 编写了一个阅读器应用程序offscreenPageLimit
,其中我有
override fun getItem(position: Int) = ComicFragment.newInstance(index = position + 1)
这里创建了一个index
大于 2000 的 ComicFragment,具有此类索引的漫画将被加载到片段中。setRetainInstance
默认为false
同样在片段中,我transMode
在 savedInstanceState 中保存了索引和布尔值,这样当用户来回滑动几页时,他们将拥有与原来相同的页面状态。它还将维护配置更改的状态。
问题是,随着从TooLargeTool中滑走的每个片段,
D/TooLargeTool: ComicFragment.onSaveInstanceState wrote: Bundle126358192 contains 4 keys and measures 0.8 KB when serialized as a Parcel
* androidx.lifecycle.BundlableSavedStateRegistry.key = 0.1 KB
* transMode = 0.0 KB
* android:user_visible_hint = 0.1 KB
* android:view_state = 0.6 KB
* fragment arguments = Bundle247579945 contains 1 keys and measures 0.0 KB when serialized as a Parcel
* index = 0.0 KB
0.8 KB 不算大,但是在viewpager 的父fragment 和它的容器activity 中积累起来的。这意味着从索引 1 浏览到 1000 时,将有 800 KB 保存在父片段的状态。当我开始一个新活动时,它到达了 1MB TransactionTooLargeException 的红线。(实际上,即使捆绑包大约 500KB 也可能发生此异常)
更糟糕的是父片段中的状态包没有释放。我发现通过这样的实现,如果我从 1 浏览到 100 然后反向返回到 1,保存的状态可以应用于每个片段但不会释放,因为父片段中状态包的大小加倍为 160 KB 而不是 80 KB。
我几乎没有在包中放任何东西,也不敢添加任何更大的东西,比如可序列化的,因为本机android:view_state
可能足以引起问题。
我想知道应该如何改进实现,是否可以轻松修复,或者更重的东西,例如使用 Android 架构组件、ViewPager2 或其他依赖项。
更新:
我试过了
view.isSaveFromParentEnabled = false
在onViewCreated()
.savedInstanceState?.clear()
在结束时onViewCreated()
。android:saveEnabled="false"
到那些具有 id 的视图,但不需要保存。
在这三种方式中,只有第三种有效。
D/TooLargeTool: ComicFragment.onSaveInstanceState wrote: Bundle242738747 contains 1 keys and measures 0.1 KB when serialized as a Parcel
* androidx.lifecycle.BundlableSavedStateRegistry.key = 0.1 KB
* transMode = 0.0 KB
* fragment arguments = Bundle232075608 contains 1 keys and measures 0.0 KB when serialized as a Parcel
* index = 0.0 KB
android:view_state
已完全消除,因为我没有任何需要保持状态的视图(EditText、ToggleButton)。
这个问题还没有完全解决,但我相信现在异常的机会已经降低了 8 倍,而不会影响功能。