androiddata-bindingandroid-databinding2-way-object-databinding

Android Two-way data binding AdapterViewBindingAdapter (ListView)


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 
    }

Solution

  • 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: