power-adapters
power-adapters copied to clipboard
Let ItemAdapter supply item IDs
For some applications, having stable item IDs is necessary. Currently if a PowerAdapter with stable IDs is composed with a ViewFactory
or varargs layoutResources
, it'll lose its stable item IDs as ItemAdapter
doesn't support it. I think a way to supply item IDs when using the append()
methods would be helpful. Maybe for layoutResources
, have them default to the layout res (which is an int
)?
This is part of a wider problem, which is ensuring composed adapters with stable item IDs form a composite adapter whose ID ranges don't accidentally overlap. If they overlapped it'd result in strange behavior in RecyclerView
, which would be difficult to debug. I also don't want users to have to worry about stable IDs outside of overriding getItemId()
. Adding your suggestion would compromise that and force the user to be aware of the full item ID range within the composite PowerAdapter
.
Consider this related problem: what if your model IDs are strings? Many systems use UUIDs.
My thoughts right now are to change PowerAdapter.getItemId()
to return an Object
instead. Since an Object
is unique in the system, any headers/footers would automatically have a stable ID. The challenge is how to map the objects into a range of long
s in a way that isn't prone to memory leaks, and has decent performance.
Added #50 to track this potential solution.
Object
item IDs would be a wonderful solution, as then they'd have basically infinite levels of scope. But yeah, no idea how they could be mapped to long
s effectively.
Another idea: What if, as part of the hasStableIds()
contract, PowerAdapter
s could specify a range of IDs needed? For example:
@Override
protected long getItemIdUpperBound() {
// Maybe my list will always be reasonably small, so:
return 100000;
// Or maybe it's a list of up to 5 items:
return 4;
// Or maybe I have no idea, and my IDs are hard to predict:
return Long.MAX_VALUE;
}
That adapter's long getItemId()
must then only return values between 0 and getItemIdUpperBound()
. Maybe throw an IllegalStateException
if it returns something outside.
Then, we could verify on every adapter composition that the sum of every adapter's count doesn't exceed LONG.MAX_VALUE
. So an adapter with getMaximumItemIds() = Long.MAX_VALUE
is fine, but if it's composed with another adapter and stable IDs are needed, throw an IllegalStateException
or something. The effective getItemId()
would be the composed PowerAdapter's getItemId()
plus getItemIdUpperBound() + 1
for every PowerAdapter that comes before it.
ViewFactory
s or varargs layoutResources
would have getItemIdUpperBound() = viewCount - 1
and getItemId() = indexOfView
.
It's not perfect, but it would enable a lot of cases where IDs are known and bounded (like incrementing database IDs or ViewFactory
s). And it wouldn't be necessary to specify when stable IDs aren't needed.
This unfortunately wouldn't cover many common cases, such as string IDs, or even integer IDs generated on a remote database, since communicating the bounds typically wouldn't be possible.
Thankfully, I think object IDs are possible using a WeakHashMap
and/or WeakReference
s.