Hey, Im writing a adapter for android sharedprefer...
# coroutines
u
Hey, Im writing a adapter for android sharedpreferences listener into flow
Copy code
private fun SharedPreferences.onSharedPreferenceChangedFlow(): Flow<String> {
    return callbackFlow {
        val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
            trySend(key)
        }
        registerOnSharedPreferenceChangeListener(listener)
        awaitClose { unregisterOnSharedPreferenceChangeListener(listener) }
    }
}
seems to work, however I do know there is one nasty behavior of the
SharedPreferences.registerOnSharedPreferenceChangeListener
, that it only keeps weak references, so the listener might get gc-ed so I need to hard reference the listener How would I turn it into a field? Or rather, I think I need a proper CallbackFlow subclass, not just use the builder, right? And looking at sources, everything is private / internal api
t
I think that the listener reference won't be GC-ed even if
registerOnSharedPreferenceChangeListener
only keeps weak references. You listener reference is captured by the lambda you passed to
awaitClose
, hence there is an implicit strong reference keeping it alive as long as the `callbackFlow`'s channel is open.
1
a
You might also consider using androidx datastore instead, which is already flow-native and avoids a ton of design pitfalls SharedPreferences has
u
I'm aware of the datastore, let's just keep it as the weak ref exercise Btw @tseisel thats interesting, because actually I'm rewriting a rxjava adapter or this, and there I explicitly read to do a Observable subclass, i.e. not to use the
create
builder -- and in that builder there is equivalent
setCancellable
which by your sound logic was doing the same..
Also, to be honest, I'm not sure super which of the
send
variants should I be using here
t
@ursus You may be right, I just found in my own code that I kept references to listeners in a Set... I may have had the issue earlier 😅 Regarding the `send`function, your only options are
trySend
and
trySendBlocking
since you are in a non-suspending context. I suggest using
trySend
most of the time, unless you absolutely don't want to miss any value (that may happen if you use
buffer
with a small capacity)
u
so were sure about the capture keeping the listener alive? @send, so the difference if the upstream is overactive, trySendBlocking blocks it on bakcpressure, trySend drops it?