Code Monkey home page Code Monkey logo

flow-preferences's People

Contributors

achep avatar jonapoul avatar obolrom avatar tfcporciuncula avatar ubadahj avatar whosnickdoglio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

flow-preferences's Issues

kotlinx.coroutines.JobCancellationException: FlowSubscription was cancelled

I recently migrated a class that uses https://github.com/f2prateek/rx-preferences to now use FlowPreferences. In our app, when the user logs out, we clear all SharedPreferences. During the logout, the app is crashing with the following exception:

kotlinx.coroutines.JobCancellationException: FlowSubscription was cancelled; job=FlowSubscription{Cancelled}@bed4c69

There isn't really any more details regarding the stack trace. I suspect I am running into Kotlin/kotlinx.coroutines#974 which may make sense given FlowSharedPreferences.keyFlow is implemented as such:

  val keyFlow = callbackFlow {
    val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> offer(key) }
    sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
    awaitClose { sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) }
  }

Something tells me that the offer(key) is being performed after the Channel has been closed.

Random NPEs

Hey, we are getting random NPEs on:

java.lang.NullPointerException: Attempt to invoke interface method 'void android.content.SharedPreferences$OnSharedPreferenceChangeListener.onSharedPreferenceChanged(android.content.SharedPreferences, java.lang.String)' on a null object reference
at androidx.security.crypto.EncryptedSharedPreferences$Editor.notifyListeners(EncryptedSharedPreferences.java:349)
at androidx.security.crypto.EncryptedSharedPreferences$Editor.apply(EncryptedSharedPreferences.java:325)
at com.tfcporciuncula.flow.StringPreference.set(StringPreference.kt:17)
at com.tfcporciuncula.flow.StringPreference.set(StringPreference.kt:7)

I'm pretty sure it revolves around SharedPreferences.java:367 ff.:

/**
    * Registers a callback to be invoked when a change happens to a preference.
    *
    * <p class="caution"><strong>Caution:</strong> The preference manager does
    * not currently store a strong reference to the listener. You must store a
    * strong reference to the listener, or it will be susceptible to garbage
    * collection. We recommend you keep a reference to the listener in the
    * instance data of an object that will exist as long as you need the
    * listener.</p>
    *
    * @param listener The callback that will run.
    * @see #unregisterOnSharedPreferenceChangeListener
    */
   void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);

So I would suggest changing FlowSharedPreferences.kt:19-23

  internal val keyFlow: KeyFlow = callbackFlow {
    val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> offer(key) }
    sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
    awaitClose { sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener) }
  }

to

private lateinit var sharedPreferencesListener: SharedPreferences.OnSharedPreferenceChangeListener

 internal val keyFlow: KeyFlow = callbackFlow {
   sharedPreferencesListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> offer(key) }
   sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferencesListener)
   awaitClose { sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferencesListener) }
 }

I tried opening a PR myself but I haven't setup my github account locally right now.

Great work otherwise!

Add documentation

Should be enough to document Preference and FlowSharedPreferences.

incomprehensible flow collection

While writing a test for my implementation with FlowSharedPreferences i discovered a unexpected behavior of the Flow:

Test Code:

    @Test
    fun testBug3() = runTest {

        val tokenPreferences = getApplicationContext<MDEApplication>().getSharedPreferences("Token", Context.MODE_PRIVATE)
        val tokenPreferencesFlow = FlowSharedPreferences(tokenPreferences).apply { clear() }
        val accessTokenPreferenceFlow = tokenPreferencesFlow.getFloat("access_token", defaultValue = 0.5f)

        launch {
            Log.i("TESTX", "collection started!")
            accessTokenPreferenceFlow.asFlow()
//                .distinctUntilChanged()
                .collectLatest {
                    Log.i("TESTX", "collected: $it")
                }
        }

        launch {
            Log.i("TESTX", "setAndCommit 20")
            accessTokenPreferenceFlow.setAndCommit(20f)
            Log.i("TESTX", "setAndCommit 30")
            accessTokenPreferenceFlow.setAndCommit(30f)
            Log.i("TESTX", "setAndCommit 50")
            accessTokenPreferenceFlow.setAndCommit(50f)
        }
    }
}

Output is:

TEST: collection started!
TEST: setAndCommit 20
TEST: collected: 20.0
TEST: setAndCommit 30
TEST: setAndCommit 50
TEST: collected: 50.0
TEST: collected: 50.0

For me i see two problems:

  1. 30 is not collected
  2. 50 is collected twice

As far as i can see right know, the two issues belong together.

Why i need this fixed in any way

In my Test i need to have a start value collected on flow collection start (Value X). Then later on, a second value (Y) is set and needs to be processed by the collection also. But right now, the first value is never processed, instead the first collection is the second value (Y). The first value is skipped for some unknown reason like 30 in the example above.

Sometimes even worse:

setAndCommit X
collection started!
setAndCommit Y
collected: X

Y is never collected. Right know i really don't know whats going on. :)

Make preference key public to read

RxPreferences allows to read preference key which is useful for debug purposes. However FlowPreferences interface doesn't have preference key accessing method declaration. Would be good if this will be added in future releases.

Ability to observe any / multiple preferences at once

I would like to be able to observe any key or only a bunch of keys inside a preference file - any plans on adding this?

Something like following:

flowSharedPreferences
    .asFlow("darkTheme", "mainColor", "accentColor") // list of keys
    .onEach { 
        print(it)
     }
    .launchIn(scope)

// or following
flowSharedPreferences
    .asFlowAny() // all preference changes will be emitted here
    .onEach { 
        print(it)
     }
    .launchIn(scope)

The flow should emit a custom class that also holds the key, e.g. a simple sealed class...

Flow not updating on SharedPreferences value change

I'm having an issue where after the initial value my Flows aren't updating when a new value is saved in SharedPreferences.

I've linked to a project that reproduces it but the gist is:

       val myPref: Preference<Int> = preferences.getInt(MY_PREF_KEY)

        update_pref.setOnClickListener {
            val selection = (0..2).random()

            GlobalScope.launch { myPref.setAndCommit(selection) }
        }

        myPref.asFlow()
            // This doesn't get triggered after the initial value
            .onEach { Log.d(tag, "PREF CHANGE: $it") }
            .launchIn(GlobalScope)

Simplified project to reproduce.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.