Git Product home page Git Product logo

livecallback's People

Contributors

rih-carv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

livecallback's Issues

Sample application

Provide a simple sample application showcasing main features, behaviors and use cases

ConcurrentModificationException on recursive callback registration

Describe the bug
The library throws an exception while trying to register a recursive callback inside of its own body. I don't know if anyone would ever try to do something like this, but it would be nice to be resilient supporting this possibility of use.

To Reproduce
Steps to reproduce the behavior:

  1. Register a callback that tries to register itself again inside of its own body when invoked (achievable by creating the callback instances from a function, probably also from a computed property)
  2. Invoke the callback
  3. Then a ConcurrentModificationException is thrown

Expected behavior
The inner callback should be successfully registered for future invocations.

Context details (please complete the following information):

  • Device kind: Emulator
  • Device: Google Pixel 2
  • OS: Android 11
  • LiveCallback version: 1.0.0

Additional context
Minimal code to reproduce:

val registry = TokenizedSimpleLiveCallbackRegistry()
fun createCallback(): SimpleCallback = {
    registry.register(lifecycle, callback = createCallback())
}

val token = registry.register(lifecycle, callback = createCallback())
registry(token)

Relevant stack trace chunk:

2022-10-12 00:51:13.764 9554-9554/com.ricarvalho.livecallback E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.ricarvalho.livecallback, PID: 9554
    java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.next(ArrayList.java:860)
        at com.ricarvalho.livecallback.LiveCallbackContainer.invoke(LiveCallbackContainer.kt:72)
        at com.ricarvalho.livecallback.registry.TokenizedLiveCallbackRegistry.invoke-4goFEak(TokenizedLiveCallbackRegistry.kt:105)
        at com.ricarvalho.livecallback.registry.TokenizedInputLiveCallbackRegistry.invoke-4goFEak(TokenizedInputLiveCallbackRegistry.kt:97)

Postponable invocations

Is your feature request related to a problem? Please describe.
Today, if an invocation on registry happens while there's none matching callback registered, this invocation is lost forever.

Describe the solution you'd like
It would be nice to have the option to hold/preserve those invocations until there's at least some registered callback to handle them. Also, having a screen that showcases this behavior in the sample app would be great.

Describe alternatives you've considered
There's a draft of a possible structure that makes this request feasible at the feature/postponable branch.

Allow to invoke callbacks

Allow to invoke previously registered callbacks, distinguishing between different callback origins (declaration/instantiation locations in the code) in a way agnostic to their instances

API docs

Provide public API docs (for use inside IDE and also as a web page)

Helper extension functions

Is your feature request related to a problem? Please describe.
That would be nice to have extension functions that simplifies usages, as the structures as is may lead to some boilerplate code.

Describe the solution you'd like
There could be some extensions to:

  1. make the invocation of multiple callbacks more straightforward
  2. simplify the invocation of callbacks where a matching lambda signature is expected (started a draft of this at feature/extensions branch)
  • This could be used like so:
    • Legacy SDK code expecting a lambda callback:
      fun doSomething(callback: (param: String) -> Unit) { /* long running operation followed by callback invocation */ }
    • User code transforming a previously registered callback seamlessly through an extension function:
      val token = registry.register(lifecycle) { /* callback code */ }
      sdk.doSomething(token asLambdaOn registry) // or sdk.doSomething(registry lambdaFor token)
    • Instead of the common current approach:
      val token = registry.register(lifecycle) { /* callback code */ }
      sdk.doSomething { registry(token, it) }
  1. make callback registration more concise and idiomatic, by automatically getting the Lifecycle/LifecycleOwner from the available scope
  • This could be used like so:
    • User code registering a callback inside of an Activity/Fragment omitting the Lifecycle parameter:
      with (registry) {
          token = register { /* callback code */ }
      }
      
      // this could be achievable in the future, when context receivers becomes stable:
      val token = registry.register { /* callback code */ }

A new module/artifact (to an opt-in usage style, like by eg. androidx.lifecycle:lifecycle-extensions) containing those extension definitions (also exposing the main module as an api transitive dependency) would be awesome!

Describe alternatives you've considered
For item 1, a simple extension function accepting a vararg/List of CallbackTokens that loops invoking each one should do.
For item 2 there's a draft at feature/extensions branch.
For item 3 it would probably be implemented like something in the following lines (I can be wrong, but I believe Kotlin allows to omit ):

// by now, inside of LiveCallbackRegistry interfaces:
fun LifecycleOwner.register(callback: Callback<I, O>) = register(lifecycle, callback = callback)

// maybe in the future, outside of the interfaces as top level extension functions:
context(LifecycleOwner)
fun LiveCallbackRegistry.register(callback: Callback<I, O>) = register(lifecycle, callback = callback)

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.