简体   繁体   中英

Android Jetpack: RecyclerView is not updating when LiveData is set

So I have a simple implementation to display a list of users in a RecyclerView , and the list is queried in a ViewModel as LiveData .

The problem is that the UI is not updated to show the latest list - called users - even when the list is observed. I just set up a list of demo users for now.

Here's my ViewModel:

class MainViewModel : ViewModel() {

    private val demoData = listOf(
            User(userName = "Bob", favoriteColor = "Green"),
            User(userName = "Jim", favoriteColor = "Red"),
            User(userName = "Park", favoriteColor = "Blue"),
            User(userName = "Tom", favoriteColor = "Yellow"),
            User(userName = "Lee", favoriteColor = "Black"),
            User(userName = "Xiu", favoriteColor = "Gray")
    )

    private val _users = MutableLiveData<List<User>>()
    val users: LiveData<List<User>>
        get() = _users

    init {
        _users.value = listOf()
    }

    fun loadUsers() {
        _users.value = demoData.toMutableList().apply { shuffle() }
    }
}

And my ViewModel's attached Fragment:

// ...

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)
    viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)

    viewModel.users.observe(this, Observer {
        mAdapter.notifyDataSetChanged()
    })

    mAdapter = UsersAdapter(viewModel.users.value!!)

    mainRV = view?.findViewById<RecyclerView>(R.id.rv_main)?.apply {
        adapter = mAdapter
        layoutManager = LinearLayoutManager(view?.context)
    }

    viewModel.loadUsers()
}

PS the UsersAdapter is a usual RecyclerView.Adapter .

I have made sure to call setValue on my users list to call the Observer, thus I am not sure what is missing here. Is my adapter wrongly setup?

fun loadUsers() {
    _users.value = demoData.toMutableList().apply { shuffle() }
}

toMutableList() creates a new list with the data, see the source code:

public fun <T> Collection<T>.toMutableList(): MutableList<T> {
    return ArrayList(this)
}

So instead of getting the initial value and never updating your adapter, you should update the list in the adapter and show that.

viewModel.users.observe(this, Observer { users ->
    mAdapter.updateData(users)
})

Where if you are not using ListAdapter , then you can define this method like this:

class MyAdapter: RecyclerView.Adapter<ViewHolder>(
   private var list: List<User> = Collections.emptyList()
) {
    ...

    fun updateData(users: List<User>) {
        this.users = users
        notifyDataSetChanged()
    }
}

You can also use ListAdapter and submitList and you'll also get animations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM