I use Jetpack Compose and have 2 screens. When I open second screen and back to the fisrt, flow variable calling again and ui updated again. But, I don't understand why... When I use liveData was working perfect.
My code with LiveData:
class MainViewModel(private val roomRepository: Repository, private val sPref:SharedPreferences) : ViewModel() {
val words: LiveData<List<WordModel>> by lazy {
roomRepository.getAllWords()
}
...
}
MainScreen.kt:
@ExperimentalMaterialApi
@Composable
fun MainScreen(viewModel: MainViewModel) {
...
val words: List<WordModel> by viewModel
.words
.observeAsState(listOf())
...
WordList(
words = words,
onNoticeClick = { viewModel.onWordClick(it) },
state = textState,
lazyState = viewModel.listState!!
)
...
}
@Composable
private fun WordList(
words: List<WordModel>,
onNoticeClick: (WordModel) -> Unit,
state: MutableState<TextFieldValue>,
lazyState: LazyListState
) {
var filteredCountries: List<WordModel>
LazyColumn(state = lazyState) {
val searchedText = state.value.text
filteredCountries = if (searchedText.isEmpty()) {
words
} else {
words.filter {
it.word.lowercase().contains(searchedText) || it.translation.lowercase()
.contains(searchedText)
}
}
items(count = filteredCountries.size) { noteIndex ->
val note = filteredCountries[noteIndex]
Word(
word = note,
onWordClick = onNoticeClick
)
}
}
}
WordDao.kt:
@Dao
interface WordDao {
@Query("SELECT * FROM WordDbModel")
fun getAll(): LiveData<List<WordDbModel>>
}
RoomRepositoryImpl.kt:
class RoomRepositoryImpl(
private val wordDao: WordDao,
private val noticeDao: NoticeDao,
private val dbMapper: DbMapper
) : Repository {
override fun getAllWords(): LiveData<List<WordModel>> =
Transformations.map(wordDao.getAll()) {dbMapper.mapWords(it)}
...
}
DbMapperImpl.kt:
class DbMapperImpl: DbMapper {
...
override fun mapWords(words: List<WordDbModel>): List<WordModel> =
words.map { word -> mapWord(word, listOf<NoticeModel>()) }
}
My code with Flow, which calling every time when open the first screen:
class MainViewModel(private val roomRepository: Repository, private val sPref:SharedPreferences) : ViewModel() {
val words: Flow<List<WordModel>> = flow {
emitAll(repository.getAllWords())
}
}
MainScreen.kt:
@ExperimentalMaterialApi
@Composable
fun MainScreen(viewModel: MainViewModel) {
...
val words: List<WordModel> by viewModel
.words
.collectAsState(initial = listOf())
...
}
WordDao.kt:
@Dao
interface WordDao {
@Query("SELECT * FROM WordDbModel")
fun getAll(): Flow<List<WordDbModel>>
}
RoomRepositoryImpl.kt:
class RoomRepositoryImpl(
private val wordDao: WordDao,
private val noticeDao: NoticeDao,
private val dbMapper: DbMapper
) : Repository {
override fun getWords(): Flow<List<WordModel>> = wordDao.getAll().map { dbMapper.mapWords(it) }
}
And my router from MainRouting.kt:
sealed class Screen {
object Main : Screen()
object Notice : Screen()
object Your : Screen()
object Favorites : Screen()
}
object MainRouter {
var currentScreen: Screen by mutableStateOf(Screen.Main)
var beforeScreen: Screen? = null
fun navigateTo(destination: Screen) {
beforeScreen = currentScreen
currentScreen = destination
}
}
And MainActivity.kt:
class MainActivity : ComponentActivity() {
...
@Composable
@ExperimentalMaterialApi
private fun MainActivityScreen(viewModel: MainViewModel) {
Surface {
when (MainRouter.currentScreen) {
is Screen.Main -> MainScreen(viewModel)
is Screen.Your -> MainScreen(viewModel)
is Screen.Favorites -> MainScreen(viewModel)
is Screen.Notice -> NoticeScreen(viewModel = viewModel)
}
}
}
...
}
Perhaps someone knows why a new drawing does not occur with liveData (or, it is performed so quickly that it is not noticeable that it is), but with Flow the drawing of the list is visible.
> = flow { emitAll(repository.getAllWords())} sould't calling again. It's working for livedata: val words: LiveData
– Alex Aug 31 '22 at 19:24> by lazy { roomRepository.getAllWords() } - executed only 1 time.
> = flow { ... HERE ... } and val words: LiveData
– Alex Aug 31 '22 at 19:53> by lazy { ... HERE ...}