Step #2: Observing Preference Changes

With our preference for the server URL, we do not need to do anything special right at the moment the user makes a change. We just get the now-current value of that URL when the user requests an import. With this new preference, though, we need to find out in real time when the user flips that Switch, so we can either schedule or cancel our periodic background import work.

To help with that, add this property to PrefsRepository:

  private val importKey = context.getString(R.string.import_key)

This pulls in the value of the doPeriodicImport string resource that we added in the previous step.

Then, add this observeImportChanges() function:

  fun observeImportChanges() = channelFlow {
    val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
      if (importKey == key) {
        offer(prefs.getBoolean(importKey, false))
      }
    }

    prefs.registerOnSharedPreferenceChangeListener(listener)
    awaitClose { prefs.unregisterOnSharedPreferenceChangeListener(listener) }
  }

SharedPreferences has a listener mechanism to find out when preference values get changed, such as via our preference screen. You can call registerOnSharedPreferenceChangeListener(), and your listener will be called with the keys that change as they change. You can use the key to pull in the latest value for the preference and do something with it. unregisterOnSharedPreferenceChangeListener() removes the listener.

observeImportChanges() wraps all of those up in a Flow, using the channelFlow() factory function. Our listener will watch for changes to the preference identified by our importKey resource. When we get a change, it will offer() that change, causing it to be emitted by the Flow that we are creating. When the Flow is no longer being collected, awaitClose() is called, and we unregister our listener.

You can learn more about channelFlow() in the "Bridging to Callback APIs" chapter of Elements of Kotlin Coroutines!

Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.