简体   繁体   中英

Use repeatOnLifecycle to collect a StateFlow's value but only receive the update when current fragment resume

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.

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