Tuesday, 5 October 2021

Change of StateFlow not collected by Fragment when done in DialogFragment

I have a Fragment that opens a DialogFragment with some settings in it. When I change the settings in the DialogFragment I want the underlying Fragment to collect the changes. I use a view model and StateFlows to store the settings and have collectors set up in the Fragment, however, they are never called. But the view model is updated correctly. Is it because of the viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) that the collectors are not called because the DialogFragment is showing? But the background fragment is still active.

When I use MutableLiveData instead of MutableStateFlow and make an observer instead of the collector, it works, too. So it must be something within the coroutine.

class SomeFragment : Fragment() {
    // Dropped the other functions, e.g. onCreate, for simplicity

    val settings by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.testButton.setOnClickListener {
            val settingsFragment = SettingsDialogFragment()
            settingsFragment.show(requireActivity().supportFragmentManager, "settings")
        }

        lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                settings.lowerState.collect {
                    Log.e("DEBUG", "lowerState switched")
                }
                settings.upperState.collect {
                    Log.e("DEBUG", "upperState switched")
                }
            }
        }
    }
}
class SettingsViewModel(application: Application) : AndroidViewModel(application) {

    val lowerState: MutableStateFlow<Boolean> = MutableStateFlow(true)
    val upperState: MutableStateFlow<Boolean> = MutableStateFlow(true)
}

The dialog fragment is a simple dialog with no special functions

class SettingsDialogFragment : DialogFragment() {

    private var _binding: FragmentSettingsDialogBinding? = null
    private val binding get() = _binding!!

    private val settings: SettingsViewModel by activityViewModels()

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        _binding = FragmentRecordingSettingsDialogBinding.inflate(
            layoutInflater,
            null,
            false
        )
        _binding!!.settings = settings

        val builder = AlertDialog.Builder(requireActivity())

        return builder.setView(binding.root).create()
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="settings"
            type="com.example.SettingsViewModel"/>
    </data>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <androidx.appcompat.widget.SwitchCompat
                android:checked="@={settings.upperState}"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <androidx.appcompat.widget.SwitchCompat
                android:checked="@={settings.lowerState}"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
</layout>


from Change of StateFlow not collected by Fragment when done in DialogFragment

No comments:

Post a Comment