kozmi55 / Flexible-RecyclerView-with-Databinding

A RecyclerView Adapter that can handle multiple item types without much boilerplate and can be reused on any screen with list content.
Apache License 2.0
28 stars 15 forks source link

Adding new items does not update the view #2

Closed cmhernandezdel closed 2 years ago

cmhernandezdel commented 3 years ago

Hello, first of all thanks for the great tutorial.

I have tried to implement this databinding RecyclerView and I managed to understand it and load the data. However I have a problem: I have this RecyclerView in a fragment, then I open another activity (without finishing current) to add a new item, I add it successfully to the database and when I come back to my list fragment, the RecyclerView does not reflect the changes.

I do not know where the problem actually lies, but since we only call the loadDevices function on the init method of the ViewModel, obviously it will not take the changes from the database. Also, notifyDatasetChanged is only called from the BindingAdapter.

Previously, I was using Flow and it worked well, but I like your approach more, so how should we notify when adding, editing or deleting an item?

Thank you.

kozmi55 commented 3 years ago

Hi,

You can implement this with Flow as well. The binding doesn't depend on what method you use to load data. I would suggest using Flow, and when you add a new item, the Flow will produce new data, what will set the LiveData in the ViewModel, and then the UI will update.

Alternatively if you want to stick with this method of loading data, you can implement a way to notify the Fragment that the data has changed, and then in the Fragment call a method on the ViewModel to reload the data.

cmhernandezdel commented 3 years ago

Hi again,

I ended up going back to flows. I share the code of the ViewModel in case it could help future readers:

@HiltViewModel
class CarListViewModel @Inject constructor(
    private val carDataProvider: CarDataProvider
) : ViewModel() {

    val data: LiveData<List<ItemViewModel>>
        get() = _data
    private val _data = MutableLiveData<List<ItemViewModel>>(emptyList())

    init {
        listenForDatabaseChanges()
    }

    private fun listenForDatabaseChanges() = viewModelScope.launch {
        var carFlow = carDataProvider.getCarListData() // returns a Flow<List<CarData>>
        carFlow.collect { dbList ->
            val carsByMake = dbList.groupBy { it.make }
            val viewData = createViewData(carsByMake)
           _data.postValue(viewData)
        }
    }

    private fun createViewData(carsByMake: Map<String, List<CarData>>): List<ItemViewModel> {
        val viewData = mutableListOf<ItemViewModel>()
        carsByMake.keys.forEach {
            viewData.add(HeaderViewModel(it))
            val cars = carsByMake[it]
            cars?.forEach { car: CarData ->
                val item = if (car.isAd) {
                    CarAdViewModel(car.make, car.model, car.price)
                } else {
                    CarListingViewModel(car.make, car.model, car.price)
                }
                viewData.add(item)
            }
        }

        return viewData
    }
}