簡體   English   中英

房間數據庫查詢后 LiveData 不更新觀察者

[英]LiveData not updating observer after Room database query

我有一個房間數據庫,其中有與藝術家相關的歌曲,當我從 Main Activity 溢出菜單更改藝術家時,除非我離開片段並再次返回,否則帶有顯示歌曲列表的 recyclerview 的片段不會更新。 我認為我對列表的觀察就足夠了,因為它適用於正在進行的其他更改,但這次不行。

當數據發生變化時,如何讓它更新新藝術家的歌曲?

歌曲視圖模型

 //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>>
        }
    }

MainFragment當對所有歌曲進行更改時,觀察者工作得很好,但當它完全由不同的藝術家更新時就不行了。

 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) }
        }

我發現一堆答案說要在我從 Main Activity 調用的 Fragment 中創建一個函數,但我不知道該函數會去哪里,因為我無法使適配器成為 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 的父片段。 我有什么問題嗎? 我應該這樣做有不同的方式嗎? 我試圖遵循建議的架構,而不是做一堆奇怪的工作。 我是否應該只從數據庫中獲取 allSongs 並在 songViewModel 中過濾它? 我不明白為什么 allSongs.observe 沒有得到改變。

我最終通過制作一個用於列表適配器的allArtistSongsWithRatings解決了這個問題。 我從allSongsWithRatings過濾列表以避免額外的數據庫查詢。 起初這是不成功的,因為當我嘗試過濾allSongsWithRatings時返回 null 。 事實證明,由於LiveData的工作方式,我需要在過濾之前觀察allSongsWithRatings 我在MainActivityinitializeArtist中觀察到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

        }

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM