Почему я получаю null для LiveData при повторном запуске?

#android #android-livedata

#Android #android-livedata

Вопрос:

Я получаю aMVoice от DetailViewModel и представляю это в пользовательском интерфейсе для редактирования.

Я вызываю isChanged() in FragmentDetail и проверяю, изменилось ли содержимое aMVoice.

Я не могу получить правильный результат, я обнаружил, что он val b=(mDBVoiceRepository.getVoiceById(voiceId)).value всегда возвращается null , почему? Как я могу это исправить?

Код

 class FragmentDetail : Fragment() {   
    private val mDetailViewModel by lazy {
        getViewModel {
            DetailViewModel( provideRepository(mContext), args.voiceId)
        }
    }

    fun isChanged():Boolean{
        mDetailViewModel.checkChanged()
        return mDetailViewModel.isChanged.value!!
    }
}       

class DetailViewModel(private val mDBVoiceRepository: DBVoiceRepository, private val voiceId:Int) : ViewModel() {

   val aMVoice=mDBVoiceRepository.getVoiceById(voiceId)

   private val _isChanged= MutableLiveData<Boolean>(false)
   val isChanged: LiveData<Boolean> = _isChanged

   fun checkChanged(){
         val a=aMVoice.value
         val b=(mDBVoiceRepository.getVoiceById(voiceId)).value   //It's null
        _isChanged.value=!(a==b)

   }
}
    
class DBVoiceRepository private constructor(private val mDBVoiceDao: DBVoiceDao){
    fun getVoiceById(id:Int)=mDBVoiceDao.getVoiceById(id)
}
    
interface DBVoiceDao{   
   @Query("SELECT * FROM voice_table where id=:id")
   fun getVoiceById(id:Int):LiveData<MVoice>
}
    
@Entity(tableName = "voice_table", indices = [Index("createdDate")])
data class MVoice(
    @PrimaryKey (autoGenerate = true) @ColumnInfo(name = "id") var id: Int = 0,
    var name:          String = "",
    var path:          String = ""
)
  

Комментарии:

1. val a=aMVoice.value Возвращает правильное значение?

2. Спасибо! val a=aMVoice.value возвращает правильное значение

Ответ №1:

Мне кажется, что вы используете текущие данные, не наблюдая за ними, текущие данные не передают ant-данные, за исключением того, что у них есть активный наблюдатель. Итак, вы должны создать observer в своем фрагменте вместо ручной проверки значения.

Кроме того, нет необходимости сохранять переменные, чтобы определить, изменилось ли значение, live data может сделать это за вас с помощью distinctUntilChanged() operator.

Итак, ваш код должен выглядеть примерно так, как показано ниже

 class FragmentDetail : Fragment() {
    private val mDetailViewModel by lazy {
        getViewModel {
            DetailViewModel(provideRepository(mContext), args.voiceId)
        }
    }
    
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        observeVoiceChange()
    }

    fun observeVoiceChange() {
        mDetailViewModel.checkChanged().distinctUntilChanged().observe(viewLifecycleOwner, Observer<MVoice> {
            //Do whatever you want when voice changes
        })
    }
}

class DetailViewModel(private val mDBVoiceRepository: DBVoiceRepository, private val voiceId: Int) : ViewModel() {

    fun checkChanged(): LiveData<MVoice> {
        return (mDBVoiceRepository.getVoiceById(voiceId))
    }
}

class DBVoiceRepository private constructor(private val mDBVoiceDao: DBVoiceDao) {
    fun getVoiceById(id: Int) = mDBVoiceDao.getVoiceById(id)
}

interface DBVoiceDao {
    @Query("SELECT * FROM voice_table where id=:id")
    fun getVoiceById(id: Int): LiveData<MVoice>
}


@Entity(tableName = "voice_table", indices = [Index("createdDate")])
data class MVoice(
        @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "id") var id: Int = 0,
        var name: String = "",
        var path: String = ""
)
  

как только фрагмент запускается, он должен отслеживать изменения в голосовых данных, возвращаться и работать с этими изменениями.