简体   繁体   中英

Room database - Dao - Repository - ViewModel

Writing good code between Dao - Repository - ViewModel. The function always return null value.

from Entity:

@Entity(tableName = "diabete")
class Diabete(
   @PrimaryKey(autoGenerate = true)
   @NonNull
   @ColumnInfo(name = "diabeteId")
   var id: Int,
   var date: LocalDateTime,
   var balise: String,
   var taux: Float,
   var note: String
)

from Dao:

// Obtenir la moyenne du taux selon la balise
@Query("SELECT IFNULL(avg(taux), 0.0) FROM diabete WHERE balise = :balise")
fun avgByBalise(balise: String): LiveData<Float>

from Repository:

fun avgBaliseAJeun(balise: String): LiveData<Float> {
   return dbDao.avgByBalise(balise)
}

from ViewModel:

    fun avgBaliseAJeune(balise: String): LiveData<Float> {
      val result = MutableLiveData<Float>()
      viewModelScope.launch(Dispatchers.IO) {
         val retour = repository.avgBaliseAJeun(balise)
         result.postValue(retour.value)
      }
      return result
   }

from Fragment:

val avgBaliseAJeun: Float = dpViewModel.avgBaliseAJeune("À jeun").observeAsState(initial = 0F).value

This line always return null when debugging.

All the compilation is ok.

The application crash when running.

What is missing?

Congrats on asking your first question, welcome!

A (not-so) fun thing to find out is that LiveData values can be null even if declared as non-nullable source .

The second thing to keep in mind is that upon app start up live data coming from room has a slight lag to it which means that even if the data is in Room, it will initially be null as seen is possible above. When you take the value of it then you see that it is null. It would intuitively make sense that you could use it like this but it doesn't support that.

Instead it should be used in Activities and Fragments like this:

dpViewModel.avgBaliseAJeune("À jeun").observe(this, result -> {
    //Do something with 'result'
});

further reading on live data in fragments

or if you want to use Jetpack Compose then you would use something like

val avgBaliseAJeun by dpViewModel.avgBaliseAJeune("À jeun").observeAsState()

Finally I see your viewModel code is converting live data to mutablelivedata, but instead of that I recommend using the live data as a read only pipe flowing out of the repostiory/Room. Then separately make a function to change the value by inserting/updating to Room through the Dao. You can do that anywhere in the code and then the live data will observe those changes.

Google has some great codelabs to check out some samples with Room, LiveData, Flow, ViewModels (though not always all at once). Feel free to follow up here more as well!

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