Reputation: 55
I'm facing a very strange behavior when using Kotlin Coroutines Flow, Room and Live Data. Whenever I turn off my device for about 5-10s and turn it back on, the Coroutines Flow re-run all over again without any trigger. I'm not sure if it's a feature provided by Google or not. My code is as below.
MainActivity
wordViewModel = ViewModelProvider(this).get(WordViewModel::class.java)
wordViewModel.allWords.observe(this, Observer { words ->
words?.let { adapter.setWords(it) }
})
WordViewModel
class WordViewModel(private val repository: WordRepository) : ViewModel() {
val allWords = repository.allWords.onEach { Log.v("WordViewModel", "Flow trigger again") }.asLiveData()
}
WordRepository
class WordRepository(private val wordDao: WordDao) {
val allWords: Flow<List<Word>> = wordDao.getAlphabetizedWords()
suspend fun insert(word: Word) {
wordDao.insert(word)
}
}
WordDao
@Dao
interface WordDao {
@Query("SELECT * from word_table ORDER BY word ASC")
fun getAlphabetizedWords(): Flow<List<Word>>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(word: Word)
}
Word
@Entity(tableName = "word_table")
data class Word(@PrimaryKey @ColumnInfo(name = "word") val word: String)
The LogCat V/WordViewModel: Flow trigger again
will be printed out again when I turn off my device for about 5-10s and turn it back on. Also, the device I'm using to test is Sony XZ2 run on Android 10.
If anyone know why this is happening, please help me understand. Thanks and sorry for my english.
EDIT
As the answer from @Alex Krafts, this feature is provided by Google. But because of my Kotlin Coroutines Flow will be combine with a network request. Therefore, I don't want it run again when device become active. I wrote a custom asLiveData() extension function for this case as follow.
LiveDataExtension
fun <T> Flow<T>.asLiveData(scope: CoroutineScope): LiveData<T> {
val liveData = MutableLiveData<T>()
scope.launch {
collect {
liveData.value = it
}
}
return liveData
}
WordViewModel
class WordViewModel(private val repository: WordRepository) : ViewModel() {
val allWords = repository.allWords.onEach { Log.v("WordViewModel", "Flow trigger again") }.asLiveData(viewModelScope)
}
Upvotes: 5
Views: 3330
Reputation: 525
This feature is indeed provided by Google. You are providing MainActivity
(this) as LifecycleOwner
in
wordViewModel.allWords.observe(this, Observer { words ->
so when you turn off device screen, activity (due to its own lifecycle) stops observing allWords
and observe it again when you turn device screen back on. So that's where your logs come from.
From the documentation
After a cancellation, if the LiveData becomes active again, the upstream flow collection will be re-executed.
Upvotes: 2