I wrote a reader app using ViewPager with offscreenPageLimit
default to 1 and FragmentStatePagerAdapter, in which I have
override fun getItem(position: Int) = ComicFragment.newInstance(index = position + 1)
Here a ComicFragment is created with an index
which could be larger than 2000, comic with such index will be loaded in the fragment. The setRetainInstance
is default to false
Also in the fragment, I saved the index and a Boolean transMode
in the savedInstanceState, so that when users swipe a few pages aways and back, they will have the page in the same state as it was. Also it will maintain the state on configuration changes.
The problem is, with every fragment swiped away, from TooLargeTool, there is
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 is not big, but it accumulates in the parent fragment of viewpager, and its container activity. Which means when browsing from index 1 to 1000, there will be 800 KB saved in the state of parent fragment. Here it reaches the red line of 1MB of TransactionTooLargeException when I start a new activity. (Actually, this exception could happen even when the bundle is around 500KB)
What's even worse is the state bundle in the parent fragment is not released. I found with such implementation, if I browse from 1 to 100 then reversely back to 1, saved state can be applied to each fragment but not released, as size of state bundle in parent fragment is doubled as 160 KB rather than 80 KB.
I barely put anything in the bundle and dare not to add anything larger like a serializable, as the native android:view_state
is potentially enough to cause problem.
I wonder how should the implementation be improved, can it be easily fixed, or something heavier like using Android Architecture Components, ViewPager2, or other dependencies.
Update:
I've tried
view.isSaveFromParentEnabled = false
inonViewCreated()
.savedInstanceState?.clear()
at the end ofonViewCreated()
.android:saveEnabled="false"
to those views with id, but no need to be saved.
Among all these three ways, only the 3rd one works.
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
has been totally eliminated, as I don't have any view (EditText, ToggleButton) that needs to keep the state.
The issue is still not fully resolved, but I believe the chance of exception now has been lowered 8 folds without functional compromise.