Fixed
Status Update
Comments
ya...@google.com <ya...@google.com> #2
Found the issue, ugh
Noticed that when I do the following:
transaction.addToBackStack(null)
When adding a Fragment with ViewPager2, the above issue occurs, although, idk if it's becaugh of gcFragments() anymore.
As soon as I un-comment that line, the issue disappears.
Noticed that when I do the following:
transaction.addToBackStack(null)
When adding a Fragment with ViewPager2, the above issue occurs, although, idk if it's becaugh of gcFragments() anymore.
As soon as I un-comment that line, the issue disappears.
jb...@google.com <jb...@google.com> #3
Is the Sample application, to reproduce, move back really fast between page 2 -> 1 and vice versa (they are bottom buttons) a couple times.
Wait a couple seconds and page 1 (the black page) should turn white meaning the Fragment has been removed.
As soon as you comment line 40 on MainActivity, and attempt again, the error does not persist
ya...@google.com <ya...@google.com> #4
Woops, sorry, If you guys had the previous ViewPagerCrash test app, I forgot to push (was exhasuted after debugging) I pushed one more time for the latest reproducible code
ya...@google.com <ya...@google.com> #5
We'll have a look, thanks for reporting and repro steps / sample app. Stay tuned for updates on this issue.
jb...@google.com <jb...@google.com> #6
Got to debug this now. Your sample indeed showcases an issue, so thanks for reporting and for the sample!
`transaction.addToBackStack(null)` adds the Fragment replacement transaction to the back stack, so you can go back to the previous state with the back button. Is that what you were looking to achieve? You said it works without it, which might help in the meantime.
Would you mind describing the use-case, so I better understand what you're trying to achieve? E.g. in the example, by switching between buttons 1 and 2 at some point you achieve multiple stack entries going back to the ViewPager2 Fragment.
`transaction.addToBackStack(null)` adds the Fragment replacement transaction to the back stack, so you can go back to the previous state with the back button. Is that what you were looking to achieve? You said it works without it, which might help in the meantime.
Would you mind describing the use-case, so I better understand what you're trying to achieve? E.g. in the example, by switching between buttons 1 and 2 at some point you achieve multiple stack entries going back to the ViewPager2 Fragment.
ap...@google.com <ap...@google.com> #7
Mostly for my notes, but the trace below explains what happens. Still need to work out why.
We have 5 instances of FragmentStateAdapter below.
Notice how in lines 36-39 4 different instances of FragmentStateAdapter perform a scheduled gc (after grace period expires).
Those don't have the Fragments bound to their ViewHolders as those were removed: lines 8, 16, 24, 32.
At the same time, com.test.myapplication.VPAdapter.createFragment(ViewPagerFragment.kt:161) only gets called once, so presumably all 5 have a reference to that same Fragment.
Needs more investigation as looks fishy.
1 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11289)'
2 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
3 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
4 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
5 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:235)
6 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:240)
7 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
8 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onViewRecycled(FragmentStateAdapter.java:391)
9 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11307)'
10 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
11 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
12 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
13 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:235)
14 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:240)
15 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
16 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onViewRecycled(FragmentStateAdapter.java:391)
17 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11314)'
18 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
19 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
20 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
21 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:235)
22 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:240)
23 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
24 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onViewRecycled(FragmentStateAdapter.java:391)
25 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11316)'
26 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
27 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
28 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
29 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:235)
30 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:240)
31 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
32 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onViewRecycled(FragmentStateAdapter.java:391)
33 {FragmentStateAdapter@11,317}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11318)'
34 {FragmentStateAdapter@11,317}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
35 {FragmentStateAdapter@11,317}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
36 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.gcFragments(FragmentStateAdapter.java:221)
37 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.gcFragments(FragmentStateAdapter.java:221)
38 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.gcFragments(FragmentStateAdapter.java:221)
39 {FragmentStateAdapter@11,317}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.gcFragments(FragmentStateAdapter.java:221)
We have 5 instances of FragmentStateAdapter below.
Notice how in lines 36-39 4 different instances of FragmentStateAdapter perform a scheduled gc (after grace period expires).
Those don't have the Fragments bound to their ViewHolders as those were removed: lines 8, 16, 24, 32.
At the same time, com.test.myapplication.VPAdapter.createFragment(ViewPagerFragment.kt:161) only gets called once, so presumably all 5 have a reference to that same Fragment.
Needs more investigation as looks fishy.
1 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11289)'
2 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
3 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
4 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
5 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:235)
6 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:240)
7 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
8 {FragmentStateAdapter@11,288}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onViewRecycled(FragmentStateAdapter.java:391)
9 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11307)'
10 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
11 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
12 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
13 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:235)
14 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:240)
15 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
16 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onViewRecycled(FragmentStateAdapter.java:391)
17 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11314)'
18 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
19 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
20 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
21 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:235)
22 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:240)
23 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
24 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onViewRecycled(FragmentStateAdapter.java:391)
25 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11316)'
26 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
27 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
28 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
29 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:235)
30 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:240)
31 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
32 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onViewRecycled(FragmentStateAdapter.java:391)
33 {FragmentStateAdapter@11,317}.mItemIdToViewHolder will be modified at FragmentStateAdapter.<init>(FragmentStateAdapter.java:85). Current value = 'null'. New value = 'instance of androidx.collection.LongSparseArray(id=11318)'
34 {FragmentStateAdapter@11,317}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.itemForViewHolder(FragmentStateAdapter.java:234)
35 {FragmentStateAdapter@11,317}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.onBindViewHolder(FragmentStateAdapter.java:174)
36 {FragmentStateAdapter@11,306}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.gcFragments(FragmentStateAdapter.java:221)
37 {FragmentStateAdapter@11,313}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.gcFragments(FragmentStateAdapter.java:221)
38 {FragmentStateAdapter@11,315}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.gcFragments(FragmentStateAdapter.java:221)
39 {FragmentStateAdapter@11,317}.mItemIdToViewHolder will be accessed at FragmentStateAdapter.gcFragments(FragmentStateAdapter.java:221)
Description
Component used: androidx.transition
Version used: 1.4.0
Devices/Android versions reproduced on: all
If you do transitions on two sibling ViewGroups, A and B. A starts a transition on its root view, then B starts a transition. Inside of A's onTransitionEnd call back, if you start another transition on ViewGroup A, it will pause the Animators on the transition of ViewGroup B, which means the transition on B never ends.
Since two transitions with different sceneRoots should not interfere with one another, the expectation is that the transition on ViewGroup B does not get paused when by anything happening in ViewGroup A.
Not sure if this helps, but when starting another transition on ViewGroup A, the here which returns the animator associated with ViewGroup B.
pause()
inTransition
makes a call togetRunningAnimators()
In the attached sample you can see that the transition run on the
container
view group never ends.