When I collect a StateFlow's value in repeatOnLifecycle, I have to navigate to other fragment and back then can collect the value's change. But not once the value has been changed the collect lambda receives the change immediate without resume the current fragment. How can I solve this?
// Dao.kt
@Dao
interface AppDao {
// other codes
@Query("SELECT * FROM Property")
fun getAllProperties(): Flow<List<Property>>
// other codes
}
Repository with Singleton pattern and provide functions in above AppDao.
ViewModel:
class PropertyViewModel : ViewModel() {
private val repository = AppRepository.get()
private val _properties: MutableStateFlow<List<Property>> = MutableStateFlow(emptyList())
val properties: StateFlow<List<Property>> = _properties
// or ⬇️ this way still not work
// val properties: StateFlow<List<Property>>
// get() = _propertis.asStateFlow()
init {
viewModelScope.launch {
repository.getAllProperties().collect {
_properties.value = it
}
}
}
// other codes
}
Fragment:
class SomeFragment : Fragment() {
private var _binding: FragmentPropertyBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private val propertyViewModel: PropertyViewModel by viewModels()
// onCreate lifecycle method here
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// other codes
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.lifecycleScope.repeatOnLifecycle(Lifecycle.State.CREATED) {
propertyViewModel.properties.collect { propertis: List<Property> ->
// 🔴 Here I can only collet the propertis list when I go to other framgent/ or Home and then back to this fragment
// todo something
}
}
}
propertyViewModel.properties
.flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.CREATED)
.onEach {
// 🔴 and this way is identical to the repeatOnLifecycle method
Log.e("Database flowWithLifecycle", it.toString())
}
.launchIn(viewLifecycleOwner.lifecycleScope)
}
// other override lifecycle methods
}
How can I modify the code to collect the values once it's value has been changed with out leaving the current fragment and back?
using different lifecycleScope to test the collect and confirmed the value in ViewModel collected the up-to-date value once it be modifed.
Expect to collect the values in fragment once it's value has been changed with out leaving the current fragment and back?
StateFlow
has Strong equality-based conflation, from the documentation:
Values in state flow are conflated using Any.equals comparison in a similar way to distinctUntilChanged operator. It is used to conflate incoming updates to value in MutableStateFlow and to suppress emission of the values to collectors when new value is equal to the previously emitted one. State flow behavior with classes that violate the contract for Any.equals is unspecified.
using it with mutable data types can cause issues. I recommend switching to immutable data types.