Android Two-way data binding AdapterViewBindingAdapter (ListView)

471 Views Asked by At

I have a ListView and trying to use two-way data binding to set the selectedItemPosition in a ViewModel using Two-Way Attributes

But the problem is it doesn't work, the selected item doesn't set in the Value of the liveData, I tried to observe it and the value never changes when i select an item in the listView

data binding in XML:

        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="@dimen/_150sdp"
            android:nestedScrollingEnabled="true"
            tools:listheader="@tools:sample/lorem"
            tools:visibility="visible"
            android:choiceMode="singleChoice"
            android:selectedItemPosition="@={viewModel.chosenPosition}" />

in the ViewModel:

   val chosenPosition = MutableLiveData<Int>()

in the Fragment:

binding.viewModel = viewModel
binding.lifecycleOwner = viewLifecycleOwner

binding.teamsListView.adapter = ArrayAdapter(
                context,
                R.layout.list_item_choice, teamsNames
            )

viewModel.chosenPosition.observe(viewLifecycleOwner) {
        Timber.d("chosen position = $it") //never triggers when I select an item in the ListView 
    }
2

There are 2 best solutions below

4
Zain On BEST ANSWER

Problem:

android:selectedItemPosition is triggered whenever an item is selected (this doesn't implicitly include that the item is clicked/checked.

Using android:selectedItemPosition as a two-way data binding in a ListView doesn't actually automatically triggered when an item is selected, and therefore the LiveData doesn't get triggered.

You can see that when you create a normal ListView without any data binding; when you click an item, this won't trigger the selection, notice the below when an item is clicked (nothing get highlighted with a different color):

Solution:

In order to solve that for the sake of data binding, you need to explicitly do select the that item whenever it is clicked by registering OnItemClickListener to the ListView:

binding.listView.setOnItemClickListener { _, _, position, _ ->
    if (position >= 0) { // avoid -1 position calls
        binding.listview.requestFocusFromTouch()
        binding.listview.setItemChecked(position, true)
        binding.listview.setSelection(position)
    }
}

This way the live data will be set to the current selected position:

Notice when an item is selected, it's now highlighted with a light grey that is because the selection is enabled:

1
Taha Körkem On

Make sure that you have not forgetten to set your binding lifecycleOwner in your fragment

binding.lifecycleOwner = this