0

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?

shawshuai
  • 15
  • 5
  • is `Property` immutable and does it properly implement equals/hashcode (or is it data class)? – LordRaydenMK Jan 08 '23 at 15:04
  • 1
    Yes it is a data class. 2 of 3 of the Model class `Property` set be `var` before, and I change it to `val` now. And changed the method to modify the datas in `Adapter`. Now the list can be collect immediately after modify one of the `property` in the list. Thank you! – shawshuai Jan 09 '23 at 01:40

1 Answers1

1

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.

LordRaydenMK
  • 13,074
  • 5
  • 50
  • 56