试图让 RecyclerView 使用不同的数据集
Trying to get RecyclerView to use a diffferent dataset
我一直在努力弄清楚如何更新我的 RecyclerView 显示的列表。
我想做的是在更改微调器时显示已显示列表的子集。我的数据库中有一组动物,有些动物的 pet
属性设置为 true
,其他动物的属性设置为 false
.
将 Room Database 与存储库和 viewModels 结合使用,我一直在努力拼凑的是,拥有三个我可以调整的不同列表是很好的,所以在 m
存储库:
class AnimalRepository(private val animalDao: AnimalDao) {
val allAnimals: Flow<List<Animal>> = animalDao.getAnimalsByCategory()
val pets: Flow<List<Animal>> = animalDao.getAnimalsByPetStatus(true)
val nonPets: Flow<List<Animal>> = animalDao.getAnimalsByPetStatus(false)
@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun insert(animal: Animal) {
animalDao.insert(animal)
}
@WorkerThread
suspend fun get(id: Int): Animal {
return animalDao.get(id)
}
@WorkerThread
suspend fun delete(id: Int) {
animalDao.delete(id)
}
}
视图模型
class AnimalViewModel(private val repository: AnimalRepository) : ViewModel() {
var allAnimals: LiveData<List<Animal>> = repository.allAnimals.asLiveData()
val pets: LiveData<List<Animal>> = repository.pets.asLiveData()
val nonPets: LiveData<List<Animal>> = repository.nonPets.asLiveData()
var result: MutableLiveData<Animal> = MutableLiveData<Animal>()
var mode: VIEW_MODES = VIEW_MODES.BOTH
/*
* Launching a new coroutine to insert the data in a non-blocking way
* */
fun insert(animal: Animal) = viewModelScope.launch {
repository.insert(animal)
}
/*
* Launching a new coroutine to get the data in a non-blocking way
* */
fun get(id: Int) = viewModelScope.launch {
result.value = repository.get(id)
}
fun delete(id: Int) = viewModelScope.launch {
repository.delete(id)
}
}
class AnimalViewModelFactory(private val repository: AnimalRepository) : ViewModelProvider.Factory {
override fun <T: ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(AnimalViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return AnimalViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
在我的 MainActivity
中,我将其设置为在这三个列表中有一个观察者,并根据哪个视图模式处于活动状态(微调器设置视图模式),将该列表输入到我的RecyclerView 的 ListAdapter 的 submitList
animalViewModel.allAnimals.observe(this) { animals ->
if (viewMode == VIEW_MODES.BOTH) {
animals.let {
adapter.submitList(it)
// recyclerView.adapter = adapter
}
}
}
animalViewModel.pets.observe(this) { animals ->
if (viewMode == VIEW_MODES.PETS) {
animals.let {
adapter.submitList(it)
// recyclerView.adapter = adapter
}
}
}
animalViewModel.nonPets.observe(this) { animals ->
if (viewMode == VIEW_MODES.NON_PETS) {
animals.let {
adapter.submitList(it)
}
}
}
我正在用微调器改变模式
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when (position) {
0 -> {
viewMode = VIEW_MODES.BOTH
}
1 -> {
viewMode = VIEW_MODES.PETS
}
2 -> {
viewMode = VIEW_MODES.NON_PETS
}
}
adapter.notifyDataSetChanged()
}
如果在更改视图模式后添加或删除动物,这会正常工作,因为观察者开火并且允许正确的动物填充适配器,但 notifyDataSetChanged()
没有做任何事情,我已经一直坚持让适配器更新而不必从列表中添加或删除
我也尝试在观察器中重置适配器,但也没有任何作用
我对 kotlin 和 android 编程非常陌生,我确定我这样做是错误的,但是有没有办法强制刷新列表?
更新:
我想我可能已经找到了一个解决方案,但我担心它是 hacky。在我的 ViewModel 中,我将 allAnimals
的内容替换为过滤后的列表
fun showBoth() {
allAnimals = repository.allAnimals.asLiveData()
}
fun showPets() {
allAnimals = repository.pets.asLiveData()
}
fun showNonPets() {
allAnimals = repository.nonPets.asLiveData()
}
然后在我的主要 activity 中,我更改了处理微调器更改时的逻辑,告诉视图模型执行它的操作,然后移除观察器并将其重新打开
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when (position) {
0 -> {
animalViewModel.showBoth()
}
1 -> {
animalViewModel.showPets()
}
2 -> {
animalViewModel.showNonPets()
}
}
refreshObserver()
}
private fun refreshObserver() {
animalViewModel.allAnimals.removeObservers(this)
animalViewModel.allAnimals.observe(this) { animals ->
animals.let {
adapter.submitList(it)
}
}
}
这似乎可以让回收站视图更新,但它有问题吗?
据我所知,notifyDataSetChanged
没有做任何事情是完全合理的,您在调用之前没有提交任何新数据。但是我认为你要做的是让适配器对 viewMode
.
中的变化做出反应
如果是这种情况,我建议也将您的 viewMode
作为一个 LiveData
对象,然后公开一个列表供您的适配器观察,该列表会根据 viewMode
已选中。
Transformations.switchMap(LiveData<X>, Function<X, LiveData<Y>>)
方法(或其等效的 Kotlin 扩展函数)可能会在这里为您完成大部分工作。总之,它将一个 LiveData
的值映射到另一个。因此,在您的示例中,您可以将 viewMode
映射到 allAnimals
、pets
和 nonPets
.
之一
为了清楚起见,这里有一个简单的伪代码概述:
AnimalViewModel {
val allAnimals: LiveData<List<Animal>>
val pets: LiveData<List<Animal>>
val nonPets: LiveData<List<Animal>>
val modes: MutableLiveData<VIEW_MODES>
val listAnimals = modes.switchMap {
when (it) {
VIEW_MODES.BOTH -> allAnimals
...
}
}
}
fun onItemSelected {
viewModel.onModeChanged(position)
}
viewModel.listAnimals.observe {
adapter.submitList(it)
}
我一直在努力弄清楚如何更新我的 RecyclerView 显示的列表。
我想做的是在更改微调器时显示已显示列表的子集。我的数据库中有一组动物,有些动物的 pet
属性设置为 true
,其他动物的属性设置为 false
.
将 Room Database 与存储库和 viewModels 结合使用,我一直在努力拼凑的是,拥有三个我可以调整的不同列表是很好的,所以在 m
存储库:
class AnimalRepository(private val animalDao: AnimalDao) {
val allAnimals: Flow<List<Animal>> = animalDao.getAnimalsByCategory()
val pets: Flow<List<Animal>> = animalDao.getAnimalsByPetStatus(true)
val nonPets: Flow<List<Animal>> = animalDao.getAnimalsByPetStatus(false)
@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun insert(animal: Animal) {
animalDao.insert(animal)
}
@WorkerThread
suspend fun get(id: Int): Animal {
return animalDao.get(id)
}
@WorkerThread
suspend fun delete(id: Int) {
animalDao.delete(id)
}
}
视图模型
class AnimalViewModel(private val repository: AnimalRepository) : ViewModel() {
var allAnimals: LiveData<List<Animal>> = repository.allAnimals.asLiveData()
val pets: LiveData<List<Animal>> = repository.pets.asLiveData()
val nonPets: LiveData<List<Animal>> = repository.nonPets.asLiveData()
var result: MutableLiveData<Animal> = MutableLiveData<Animal>()
var mode: VIEW_MODES = VIEW_MODES.BOTH
/*
* Launching a new coroutine to insert the data in a non-blocking way
* */
fun insert(animal: Animal) = viewModelScope.launch {
repository.insert(animal)
}
/*
* Launching a new coroutine to get the data in a non-blocking way
* */
fun get(id: Int) = viewModelScope.launch {
result.value = repository.get(id)
}
fun delete(id: Int) = viewModelScope.launch {
repository.delete(id)
}
}
class AnimalViewModelFactory(private val repository: AnimalRepository) : ViewModelProvider.Factory {
override fun <T: ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(AnimalViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return AnimalViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
在我的 MainActivity
中,我将其设置为在这三个列表中有一个观察者,并根据哪个视图模式处于活动状态(微调器设置视图模式),将该列表输入到我的RecyclerView 的 ListAdapter 的 submitList
animalViewModel.allAnimals.observe(this) { animals ->
if (viewMode == VIEW_MODES.BOTH) {
animals.let {
adapter.submitList(it)
// recyclerView.adapter = adapter
}
}
}
animalViewModel.pets.observe(this) { animals ->
if (viewMode == VIEW_MODES.PETS) {
animals.let {
adapter.submitList(it)
// recyclerView.adapter = adapter
}
}
}
animalViewModel.nonPets.observe(this) { animals ->
if (viewMode == VIEW_MODES.NON_PETS) {
animals.let {
adapter.submitList(it)
}
}
}
我正在用微调器改变模式
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when (position) {
0 -> {
viewMode = VIEW_MODES.BOTH
}
1 -> {
viewMode = VIEW_MODES.PETS
}
2 -> {
viewMode = VIEW_MODES.NON_PETS
}
}
adapter.notifyDataSetChanged()
}
如果在更改视图模式后添加或删除动物,这会正常工作,因为观察者开火并且允许正确的动物填充适配器,但 notifyDataSetChanged()
没有做任何事情,我已经一直坚持让适配器更新而不必从列表中添加或删除
我也尝试在观察器中重置适配器,但也没有任何作用
我对 kotlin 和 android 编程非常陌生,我确定我这样做是错误的,但是有没有办法强制刷新列表?
更新:
我想我可能已经找到了一个解决方案,但我担心它是 hacky。在我的 ViewModel 中,我将 allAnimals
的内容替换为过滤后的列表
fun showBoth() {
allAnimals = repository.allAnimals.asLiveData()
}
fun showPets() {
allAnimals = repository.pets.asLiveData()
}
fun showNonPets() {
allAnimals = repository.nonPets.asLiveData()
}
然后在我的主要 activity 中,我更改了处理微调器更改时的逻辑,告诉视图模型执行它的操作,然后移除观察器并将其重新打开
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when (position) {
0 -> {
animalViewModel.showBoth()
}
1 -> {
animalViewModel.showPets()
}
2 -> {
animalViewModel.showNonPets()
}
}
refreshObserver()
}
private fun refreshObserver() {
animalViewModel.allAnimals.removeObservers(this)
animalViewModel.allAnimals.observe(this) { animals ->
animals.let {
adapter.submitList(it)
}
}
}
这似乎可以让回收站视图更新,但它有问题吗?
据我所知,notifyDataSetChanged
没有做任何事情是完全合理的,您在调用之前没有提交任何新数据。但是我认为你要做的是让适配器对 viewMode
.
如果是这种情况,我建议也将您的 viewMode
作为一个 LiveData
对象,然后公开一个列表供您的适配器观察,该列表会根据 viewMode
已选中。
Transformations.switchMap(LiveData<X>, Function<X, LiveData<Y>>)
方法(或其等效的 Kotlin 扩展函数)可能会在这里为您完成大部分工作。总之,它将一个 LiveData
的值映射到另一个。因此,在您的示例中,您可以将 viewMode
映射到 allAnimals
、pets
和 nonPets
.
为了清楚起见,这里有一个简单的伪代码概述:
AnimalViewModel {
val allAnimals: LiveData<List<Animal>>
val pets: LiveData<List<Animal>>
val nonPets: LiveData<List<Animal>>
val modes: MutableLiveData<VIEW_MODES>
val listAnimals = modes.switchMap {
when (it) {
VIEW_MODES.BOTH -> allAnimals
...
}
}
}
fun onItemSelected {
viewModel.onModeChanged(position)
}
viewModel.listAnimals.observe {
adapter.submitList(it)
}