Coder Social home page Coder Social logo

Comments (17)

zsoltk avatar zsoltk commented on June 29, 2024

Nice catch! Will investigate, thanks!

from compose-router.

zsoltk avatar zsoltk commented on June 29, 2024

Findings so far:

  • There's a backStackMap inside Router.kt which holds reference to BackStack instances
  • Since BackStack is @Model, it seems it has references to Composables under the hood (it makes sense that it does), that's the source of the leak
  • Removing backStackMap means it's lost with DKA
  • Making it ambient again makes no difference, leaks the same
  • Instead of storing BackStack, an option is to only store its elements (which are then not @Model instances) and restore BackStack from elements, but this has further problems:
    • If elements are immutable list, and list operations create new lists inside BackStack, then the held reference to list won't get updated, so upon restoring from backStackMap it will restore old state
    • If elements are mutable list, then @Model cannot track changes inside that, and will not trigger a recompose.

Options at this point that I don't really want to do:

  • Force extending either Serializable or Parcelable on all sealed classes that Router can accept, so that they are persistable without app-level map directly to Bundle
  • Drop support for persisting back stack

Optimally:

  • Find a way to persist BackStack on app-level without references to Composables

Fallback:

  • Maybe make separate packages, then client code can pick whether it wants transient / serializable / parcelable Router - I've had this idea earlier

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

What do you mean by DKA?

from compose-router.

zsoltk avatar zsoltk commented on June 29, 2024

DKA = Don't Keep Activities

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

Ah OK thanks for clarification.

It seems to me that backStackMap is a global value, so technically there should be no need for storing anything in savedInstanceState? Although this would not help with the leak, just trying to understand why it's necessary now

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

Would it be possible to cache a non @Model class inside backStackMap and wrap it with a @Model class before passing it down to children?

from compose-router.

zsoltk avatar zsoltk commented on June 29, 2024

Yes, now it's global. Original intention was to store it in Bundle, but 1. it means all sealed classes need to be either Serializable or Parcelable 2. Actual elements are lightweight objects so I saw no hurt in storing them global in a trade-off for simpler client code.

Bundle on the other hand is used for more than that. You have the BundleScope @Composable which allows client code to store and retrieve data from a scoped Bundle. This is demonstrated in the example app found in app-nested-containers module. There you have the "Local data: 0" labels which are actually clickable to increase the counter. When you leave a routing behind (parent level pushes something to back stack) but come back to it (pop), that data is restored from Bundle.

What you described as caching non-@Model class is what I tried to describe above with storing only the elements of BackStack where I wrote about why neither a mutable nor an immutable list would work unfortunately.

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

I just noticed something in those logs. I think the issue is not with the @Model class. Here's what happens:

  1. Start app - onActive called
  2. Press back to quit app - onDispose NOT called
  3. Start app again - onActive called

Seems like this way Router gets leaked

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

Actually if you do this you will see same issue for onDispose not called

setContent {
    onActive {
        Log.d("ASD", "onActive")
    }
    onDispose {
        Log.d("ASD", "onDispose")
    }
}

from compose-router.

ShikaSD avatar ShikaSD commented on June 29, 2024

It is partially related to the model class, but you are right, I have checked it yesterday and noticed the same issue.

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

There's more discussion in Slack, but the workaround for now is to store a reference to Composition returned by setContent {} and then call Composition.dispose() inside onDestroy in Activity

from compose-router.

zsoltk avatar zsoltk commented on June 29, 2024

Nice! Do you want to make a PR?

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

Well this problem cannot really be solved in Router and has to be solved in client code. Plus seems like Google team is aware and said it should be fixed with next release.

from compose-router.

zsoltk avatar zsoltk commented on June 29, 2024

I meant there are 2 example apps and the main README could also make a mention of it.

from compose-router.

zsoltk avatar zsoltk commented on June 29, 2024

I just thought to have your name on it since you found the solution. If you don't feel like it, I can do it too.

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

I cannot do it just now, so you go ahead and do it :) The solution was suggested on Slack #compose ;)

from compose-router.

mvarnagiris avatar mvarnagiris commented on June 29, 2024

Closing this, because this bug is in Compose not in this library

from compose-router.

Related Issues (20)

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.