I find it hard to spot the real raison d'etre of the android.databinding.ObservableList
as a data binding feature.
At first it looked like a cool tool to display lists, through data binding, adding them via xml
to a RecyclerView
.
To do so, I made a BindingAdapter like this:
@BindingAdapter(value = {"items"}, requireAll = false)
public static void setMyAdapterItems(RecyclerView view, ObservableList <T> items) {
if(items != null && (view.getAdapter() instanceof MyAdapter)) {
((GenericAdapter<T>) view.getAdapter()).setItems(items);
}
}
This way, I can use the attribute app:items
in a RecyclerView
with a MyAdapter
set to it, to update its items.
Now the best feature of ObservableList
is you can add an OnListChangedCallback
to it, which handles the same events available in the RecyclerView
to add/move/remove/change items in it without actually reloading the whole list.
So the logic I thought to implement was the fallowing:
- I start with an empty
MyAdapter
- When my items are fetched from my APIs, I instantiate an
ObservableArrayList
wrapping them and pass it to thebinding
- Data binding invokes my
BindingAdapter
passing the items toMyAdapter
- When
MyAdapter
receives new items, it clears its old ones and adds anOnListChangedCallback
to theObservableList
received to handle micro-changes - If anything changes in the
ObservableList
,MyAdapter
will change accordingly without refreshing completely - If i want to display a completely different set of the same items type, I can just re-set the
binding
variable, so theBindingAdapter
will be invoked again andMyAdapter
items will be completely changed.
For example, if I want to display items of type Game
which I have two different lists for: "owned games" and "wishlist games", I could just call binding.setItems(whateverItems)
to completely refresh the displayed items, but for example, if I move the "wishlist games" around the list to organize them by relevance, only micro-changes will be executed within each list without refreshing the whole thing.
Turns out this idea was unfeasible because data binding re-executes the BindingAdapter
every time a single change is made to an ObservableList
, so for example I observe the fallowing behaviour:
- I start with an empty
MyAdapter
- When my items are fetched from my APIs, I instantiate an
ObservableArrayList
wrapping them and pass it to thebinding
- Data binding invokes my
BindingAdapter
passing the items toMyAdapter
- When
MyAdapter
receives new items, it clears its old ones and adds anOnListChangedCallback
to theObservableList
received to handle micro-changes - If anything changes in the
ObservableList
, theBindingAdapter
is invoked again, thusMyAdapter
receives the whole list again and completely refreshes.
This behaviour seems quite broken to me because prevents the ObservableList
from being usable within an data-bound xml
. I cannot seriously figure out a legit case in which this behaviour is desirable.
I looked up some examples: here and this other SO question
In the first link all the examples used the ObservableList
directly to the Adapter
without even passing form xml
and actual data binding, while in the code linked in the SO answer, the developer did basically the same thing I tried to do, adding:
if (this.items == items){
return;
}
at the beginning of his Adapter.setItems(ObservableList<T> items)
to discard all the cases where the method is invoked because of simple changes in the ObservableList
.
What is the need of this behaviour? What might be some cases where this behaviour is desirable? I feel like ObservableList
is a feature added with data binding and is really useful except when used with actual data binding, in which case it forces you to defend from its behaviour.
If I declare it as a simple List
in both xml
data tags and in BindingAdapter
signature, then I can cast it back to ObservableList
inside MyAdapter
and it works just fine, but this is quite a bad hack.
If it was just a separate feature from data binding, without triggering the binding at every change it would have been much better in my opinion.
ObservableList
triggers theBindingAdapter
– LucanObservableList
which is better not being used with actual databinding (i.e. set throught xml), but must be handled directly in theAdapter
? This just doesn't make sense to me, they could have done anObservableList
in theirGuava
library that notifies callbacks just like the databinding one, but doesn't rebind when passed throught xml. It's like building an object with a purpose and then deliberately break the desired behaviour. – LucanObservableList
with databinding, it can't be "just pass the thing directly to your adapter“ because then it would have been much easier just not to make it rebind every time it changes. – LucannotifyItemChanged()
orremoved()
or other notifyItem methods are never called. Whenever you change single item,notifyDataSetChanged()
method is called. Like you said, that does not make sense. I hope someone makes it more understandable. – Dumah