我有一个房间数据库,其中有与艺术家相关的歌曲,当我从 Main Activity 溢出菜单更改艺术家时,显示歌曲列表的 recyclerview 片段不会更新,除非我离开片段并再次返回。我认为我对列表的观察就足够了,因为它适用于正在进行的其他更改,但这次不行。
当数据发生变化时,我如何让它更新为新艺术家的歌曲?
songViewModel
//default artist name for this phase of production
var artistName = "Ear Kitty"
private val _artistNameLive = MutableLiveData<String>(artistName)
val artistNameLive: LiveData<String>
get() = _artistNameLive
private var _allSongs : MutableLiveData<List<SongWithRatings>> = repository.getArtistSongsWithRatings(artistNameLive.value.toString()).asLiveData() as MutableLiveData<List<SongWithRatings>>
val allSongs: LiveData<List<SongWithRatings>>
get() = _allSongs
fun changeArtist(artist: String){
_artistNameLive.value = artist
artistName = artist
updateAllSongs()
}
fun updateAllSongs() = viewModelScope.launch {
run {
_allSongs = repository.getArtistSongsWithRatings(artistNameLive.value.toString())
.asLiveData() as MutableLiveData<List<SongWithRatings>>
}
}
主要片段 当对所有歌曲进行更改时,观察者工作正常,但当它完全由不同的艺术家更新时。
songViewModel.allSongs.observe(viewLifecycleOwner) { song ->
// Update the cached copy of the songs in the adapter.
Log.d("LiveDataDebug","Main Fragment Observer called")
Log.d("LiveDataDebug",song[0].song.songTitle)
song.let { adapter.submitList(it) }
}
我发现一堆答案说要在我从主活动调用的片段中创建一个函数,但我不知道该函数会去哪里,因为我无法使适配器成为 onViewCreated 之外的成员。起初我得到一个错误,说适配器可能已经改变然后我在下面尝试了这个并得到了一个空指针异常。
主要片段
lateinit var adapter: ItemAdapter
fun notifyThisFragment(){
adapter.notifyDataSetChanged()
}
主要活动
songViewModel.changeArtist(artistList[which])
val navHostController = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
//I get the null pointer exception on the line below
val mainFrag: MainFragment = navHostController.childFragmentManager.findFragmentById(R.id.mainFragment) as MainFragment
mainFrag.notifyThisFragment()
据我了解,我的主要活动托管 navHostFragment,它是我的 MainFragment 的父片段。我在那里弄错了吗?有没有不同的方式我应该这样做?我正在尝试遵循建议的体系结构,而不是做一堆奇怪的工作。我应该只从数据库中获取所有歌曲一次并在 songViewModel 中过滤它吗?我不明白为什么 allSongs.observe 没有得到改变。
我最终通过制作我用于我的列表适配器的 allArtistSongsWithRatings 解决了这个问题。我从 allSongsWithRatings 过滤列表以避免额外的数据库查询。起初这是不成功的,因为当我尝试过滤 allSongsWithRatings 时返回 null。事实证明,由于 LiveData 的工作方式,我需要在过滤之前观察 allSongsWithRatings。我在MainActivity和initializeArtist中观察allSongsWithRatings。
主要活动
//initialize viewModel
songViewModel.allSongsWithRatings.observe(this){
songViewModel.initializeWithArtist()
}
主要片段
songViewModel.allArtistSongsWithRatings.observe(viewLifecycleOwner) { song ->
// Update the cached copy of the songs in the adapter.
Log.d("LiveDataDebug","Main Fragment Observer called")
//Log.d("LiveDataDebug",song[0].song.songTitle)
song.let { adapter.submitList(it) }
}
SongViewModel
var artistName = "Ear Kitty"
private val _artistNameLive = MutableLiveData<String>(artistName)
val artistNameLive: LiveData<String>
get() = _artistNameLive
private val _allSongsWithRatings : MutableLiveData<List<SongWithRatings>> = repository.allSongsWithRatings.asLiveData() as MutableLiveData<List<SongWithRatings>>
val allSongsWithRatings: LiveData<List<SongWithRatings>>
get() = _allSongsWithRatings
private val _allArtistSongsWithRatings = (artistNameLive.value?.let {
repository.getArtistSongsWithRatings(
it
).asLiveData()
} )as MutableLiveData<List<SongWithRatings>>
val allArtistSongsWithRatings: LiveData<List<SongWithRatings>>
get() = _allArtistSongsWithRatings
fun changeArtist(artist: String){
_artistNameLive.value = artist
artistName = artist
initializeWithArtist()
}
fun initializeWithArtist(){
var newList = mutableListOf<SongWithRatings>()
newList = allSongsWithRatings.value as MutableList<SongWithRatings>
//make sure the list isn't empty
if(newList.isNullOrEmpty()){
//handle empty list error
}else{
//list sorted by performance rating
_allArtistSongsWithRatings.value = newList.filter { it.song.artistName == artistNameLive.value } as MutableList<SongWithRatings>
allArtistSongsWithRatings.value
}
}
在适配器的 diffutil 中的 areContentsTheSame() 中添加一些检查是否足够?也许我误解了这个问题,但是如果 diffutil 设置正确,我会立即看到带有房间的实时数据。