Fixed
Status Update
Comments
em...@google.com <em...@google.com>
ry...@google.com <ry...@google.com>
sm...@google.com <sm...@google.com> #2
Thanks for the report and the example code. I understand your perspective when you say "the change is never delivered to the Adapter due to the behavior of StableIdKeyProvider".
StableIdKeyProvider is a SCOPE_CACHED style KeyProvider, and as such can't answer questions about detached items. It seems we might be able to replace OnChildAttachStateChangeListener#onChildViewDetachedFromWindow with RecyclerListener#onViewRecycled as the callback in which we clear cached information.
Shep, can you confirm that a ViewHolder's position remains valid until the holder is recycled?
Docs appear to indicate this:
/**
* This method is called whenever the view in the ViewHolder is recycled.
*
* RecyclerView calls this method right before clearing ViewHolder's internal data and
* sending it to RecycledViewPool. This way, if ViewHolder was holding valid information
* before being recycled, you can call {@link ViewHolder#getBindingAdapterPosition()} to get
* its adapter position.
*
* @param holder The ViewHolder containing the view that was recycled
*/
nam.eneim, in the mean time you can work around the problem by switching to a SCOPE_MAPPED KeyProvider. (a provider that knows the id of an item even when not attached to RecyclerView).
StableIdKeyProvider is a SCOPE_CACHED style KeyProvider, and as such can't answer questions about detached items. It seems we might be able to replace OnChildAttachStateChangeListener#onChildViewDetachedFromWindow with RecyclerListener#onViewRecycled as the callback in which we clear cached information.
Shep, can you confirm that a ViewHolder's position remains valid until the holder is recycled?
Docs appear to indicate this:
/**
* This method is called whenever the view in the ViewHolder is recycled.
*
* RecyclerView calls this method right before clearing ViewHolder's internal data and
* sending it to RecycledViewPool. This way, if ViewHolder was holding valid information
* before being recycled, you can call {@link ViewHolder#getBindingAdapterPosition()} to get
* its adapter position.
*
* @param holder The ViewHolder containing the view that was recycled
*/
nam.eneim, in the mean time you can work around the problem by switching to a SCOPE_MAPPED KeyProvider. (a provider that knows the id of an item even when not attached to RecyclerView).
na...@gmail.com <na...@gmail.com> #3
Thanks for the update. I will try using the SCOPE_MAPPED KeyProvider. It's worth noting that there is so little document about how we can use this library efficiently. I notice that the v2 is under development. Really hope it brings a lot more to the RecyclerView ecosystem.
One quick question about using the `RecyclerListener#onViewRecycled`, AFAIK, RecyclerView only allows us to set one RecyclerListener. So if the selection library needs that, does that mean the consumer App, or 3rd party library should not use its own? (This is my observation for the version I used up until now, 1.1.x or something). Or the RecyclerView has a plan to allow multiple RecyclerListener as well (which will be really helpful).
Thanks.
One quick question about using the `RecyclerListener#onViewRecycled`, AFAIK, RecyclerView only allows us to set one RecyclerListener. So if the selection library needs that, does that mean the consumer App, or 3rd party library should not use its own? (This is my observation for the version I used up until now, 1.1.x or something). Or the RecyclerView has a plan to allow multiple RecyclerListener as well (which will be really helpful).
Thanks.
sm...@google.com <sm...@google.com> #4
Have you read the package summary?
https://developer.android.com/reference/androidx/recyclerview/selection/package-summary
There is fairly extensive javadoc included in the public classes as well.
I also recall the developer relations team wrote up an article on how to use lthe selection lib, but can't seem to find it right now :)
> I notice that the v2 is under development. Really hope it brings a lot more to the RecyclerView ecosystem.
Q: Are there specific features you're looking for?
The 2.0 release is being planned largely to make some breaking API changes, e.g. remove SelectionTracker.Builder#withGestureTooltypes and SelectionTracker.Builder#withPointerTooltypes.
The main new feature I'm planning on adding in 2.0 is proper stylus support.
There is fairly extensive javadoc included in the public classes as well.
I also recall the developer relations team wrote up an article on how to use lthe selection lib, but can't seem to find it right now :)
> I notice that the v2 is under development. Really hope it brings a lot more to the RecyclerView ecosystem.
Q: Are there specific features you're looking for?
The 2.0 release is being planned largely to make some breaking API changes, e.g. remove SelectionTracker.Builder#withGestureTooltypes and SelectionTracker.Builder#withPointerTooltypes.
The main new feature I'm planning on adding in 2.0 is proper stylus support.
ap...@google.com <ap...@google.com> #5
Project: platform/frameworks/support
Branch: androidx-master-dev
commit a938a74a5ecb72f8e74bcc9a1722ac6bc07b89a2
Author: Steve McKay <smckay@google.com>
Date: Wed Jul 29 11:38:24 2020
StableIdKeyProvider improvements.
Fix bug where key/position mapping in KeyProvider was lost while entry was not yet recycled.
- In order to achieve adequate unit test coverage I added a new abstraction on-top of RecyclerView, the "ViewHost".
- Note testing could be facilitated with fewer back-flips if selection lib was in the same package as RecyclerView.
- In order to listen to recycle events we use the single use setRecyclerListener method. TODO: Add support for multiple listeners (or possibly just add a new method to OnChildAttachStateChangeListener.
Update TestAdapter to support setting setHashStableIds prior to registration of internal AdapterDataObserver.
Add some missing @NonNull, @Nullable, and @Override annotations.
Added a new single-select, stable-id based demo app.
Updated demo apps to use getAbsoluteAdapterPosition.
Remove unnecessary fancy stuff from the "Simple" demo app.
Bug: 145767095
Test: Updated StableIdKeyProviderTest to actually test stuff :)
Change-Id: If8ff8256cff49d0cbf12f2175af3c3ca62b7c68b
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTracker_SingleSelectTest.java
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/StableIdKeyProviderTest.java
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestAdapter.java
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestHolder.java
M recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java
M recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java
M recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StableIdKeyProvider.java
M samples/Support7Demos/src/main/AndroidManifest.xml
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoAdapter.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoDetailsLookup.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHeaderHolder.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHolder.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoItemHolder.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoAdapter.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/SimpleSelectionDemoActivity.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/single/DemoAdapter.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/single/DemoDetailsLookup.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/single/DemoHolder.java
A samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/single/SingleStableIdSelectionDemoActivity.java
M samples/Support7Demos/src/main/res/values/strings.xml
https://android-review.googlesource.com/1380276
Branch: androidx-master-dev
commit a938a74a5ecb72f8e74bcc9a1722ac6bc07b89a2
Author: Steve McKay <smckay@google.com>
Date: Wed Jul 29 11:38:24 2020
StableIdKeyProvider improvements.
Fix bug where key/position mapping in KeyProvider was lost while entry was not yet recycled.
- In order to achieve adequate unit test coverage I added a new abstraction on-top of RecyclerView, the "ViewHost".
- Note testing could be facilitated with fewer back-flips if selection lib was in the same package as RecyclerView.
- In order to listen to recycle events we use the single use setRecyclerListener method. TODO: Add support for multiple listeners (or possibly just add a new method to OnChildAttachStateChangeListener.
Update TestAdapter to support setting setHashStableIds prior to registration of internal AdapterDataObserver.
Add some missing @NonNull, @Nullable, and @Override annotations.
Added a new single-select, stable-id based demo app.
Updated demo apps to use getAbsoluteAdapterPosition.
Remove unnecessary fancy stuff from the "Simple" demo app.
Bug: 145767095
Test: Updated StableIdKeyProviderTest to actually test stuff :)
Change-Id: If8ff8256cff49d0cbf12f2175af3c3ca62b7c68b
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTracker_SingleSelectTest.java
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/StableIdKeyProviderTest.java
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestAdapter.java
M recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestHolder.java
M recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java
M recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java
M recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StableIdKeyProvider.java
M samples/Support7Demos/src/main/AndroidManifest.xml
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoAdapter.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoDetailsLookup.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHeaderHolder.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHolder.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoItemHolder.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoAdapter.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/SimpleSelectionDemoActivity.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/single/DemoAdapter.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/single/DemoDetailsLookup.java
M samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/single/DemoHolder.java
A samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/single/SingleStableIdSelectionDemoActivity.java
M samples/Support7Demos/src/main/res/values/strings.xml
sm...@google.com <sm...@google.com> #6
Unfortunately, due to the reliance of the fix (https://android-review.googlesource.com/1380276 ) on setRecyclerListener (which supports a single listener only), the change opens the door to potential bugs where the selection library or app author overwrite the others' registered RecyclerListener.
https://r.android.com/1381078 adds support to RecyclerView for multiple RecyclerListeners, and https://r.android.com/1384002 updates Selection lib to use the new addRecyclerListener API. But the selection lib's rc release cannot depend on an API that is not also RC or above. Given the fact that there's a work around (SCOPE_MAPPED provider, see comment#2 ) will not include a fix for this issue in the 1.1.0-rc02 release.
Will leave this bug open to track inclusion in future release.
Will leave this bug open to track inclusion in future release.
ap...@google.com <ap...@google.com> #7
Project: platform/frameworks/support
Branch: androidx-master-dev
commit 66c5c69e735df7a0540ac621e0c084ac87be0cb1
Author: Steve McKay <smckay@google.com>
Date: Fri Jul 31 14:42:15 2020
Update StableIdKeyProvider to use addRecyclerListener.
Bug: 145767095
Test: All tests passing, manual testing via demo app.
Change-Id: I21df99af34c2d34b720303858785eddb2a5314f6
M recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StableIdKeyProvider.java
https://android-review.googlesource.com/1384002
Branch: androidx-master-dev
commit 66c5c69e735df7a0540ac621e0c084ac87be0cb1
Author: Steve McKay <smckay@google.com>
Date: Fri Jul 31 14:42:15 2020
Update StableIdKeyProvider to use addRecyclerListener.
Bug: 145767095
Test: All tests passing, manual testing via demo app.
Change-Id: I21df99af34c2d34b720303858785eddb2a5314f6
M recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StableIdKeyProvider.java
ap...@google.com <ap...@google.com> #8
Project: platform/frameworks/support
Branch: androidx-master-dev
commit ce1b333030414b89b1980fa2327774af1b5416dc
Author: Steve McKay <smckay@google.com>
Date: Thu Jul 30 09:33:41 2020
Add support for multiple RecyclerListeners.
This feature is necessitated by RecyclerView-Selection dependency on listening
to recycle events.
Bug: 162504379
Test: Added new coverage.
Relnote: Add support for multiple RecyclerListeners as necessitated to fix b/145767095 affecting RecyclerView-Selection.
Change-Id: I70ad8f9bcf25c2c00fbf5f71d5a991287bef1606
M leanback/leanback/api/current.txt
M leanback/leanback/api/public_plus_experimental_current.txt
M leanback/leanback/api/restricted_current.txt
M recyclerview/recyclerview/api/current.txt
M recyclerview/recyclerview/api/public_plus_experimental_current.txt
M recyclerview/recyclerview/api/restricted_current.txt
A recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerListenerTest.java
M recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
https://android-review.googlesource.com/1381078
Branch: androidx-master-dev
commit ce1b333030414b89b1980fa2327774af1b5416dc
Author: Steve McKay <smckay@google.com>
Date: Thu Jul 30 09:33:41 2020
Add support for multiple RecyclerListeners.
This feature is necessitated by RecyclerView-Selection dependency on listening
to recycle events.
Bug: 162504379
Test: Added new coverage.
Relnote: Add support for multiple RecyclerListeners as necessitated to fix
Change-Id: I70ad8f9bcf25c2c00fbf5f71d5a991287bef1606
M leanback/leanback/api/current.txt
M leanback/leanback/api/public_plus_experimental_current.txt
M leanback/leanback/api/restricted_current.txt
M recyclerview/recyclerview/api/current.txt
M recyclerview/recyclerview/api/public_plus_experimental_current.txt
M recyclerview/recyclerview/api/restricted_current.txt
A recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerListenerTest.java
M recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
sm...@google.com <sm...@google.com> #9
Planning on the fix being released in 1.2. Should be available in 1.2.0-alpha01 in the next few weeks. No telling for sure how long it will take to get 1.2.0 to stable.
cr...@gmail.com <cr...@gmail.com> #10
With the 1.2.0-alpha01
it seems there's a new issue now, caused by the changes, that results in the holder at the top of StableIdKeyProvider.onRecycled()
to always be null. This still results in the same issue that the cache isn't updated properly and the that can cause crashes, because the lookup is wrong.
Description
- I have a RecyclerView using Selection with SelectionPredicates.createSelectSingleAnything() and StableIdKeyProvider.
- A selected item will be colored RED, unselected item will be colored GREEN.
- I select item whose adapterPosition is 0.
- I scroll the list so the item whose adapterPosition is 1 will be on top.
--> What I actually want is the item at '0' will be offscreen and will be detached, but not enough for recycle.
- I select item of adapterPosition '1'.
--> Because it is single selection list, I expect that the item of position '0' will *appear to be unselected*.
- I scroll to top and see if item of position '0' appears to be unselected or not.
Expect: item of position 0 will be colored GREEN (it should appear to be unselected), item of position 1 will be colored RED (it should appear to be selected).
Actual: item of position 0 is colored RED (it appears to be selected), item of position 1 is colored RED (it appears to be selected). (See attachment: recyclerview_selection_issue.mp4).
Note that, the item is correctly unselected, but the change is never delivered to the Adapter due to the behavior of StableIdKeyProvider (I have post about this here:
Source code:
Version used (can be found in the repo): RecyclerView 1.1.0, Selection 1.1.0-beta01.
Thanks in advance.