Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider adding rememberRetainedSaveable variant #722

Closed
alexvanyo opened this issue Jul 7, 2023 · 15 comments
Closed

Consider adding rememberRetainedSaveable variant #722

alexvanyo opened this issue Jul 7, 2023 · 15 comments
Labels
discussion Open discussions!

Comments

@alexvanyo
Copy link
Contributor

It might be possible to have rememberRetainedSaveable, a combination of rememberSaveable and rememberRetained, for preserving a state holder which won't be recreated for configuration changes, but will still save and restore instance state through process death.

The use case could be for a complex state holder that has both unbounded data that should be kept in memory through configuration changes, and some simpler data that should be saved and restored through process death.

The backing implementation could use SavedStateHandle to hook into the saved instance state.

Alternatively, this could intentionally not be provided as an API, with the expectation that a state holder like the one described above should be split into two parts: the part that is retained in memory, and the part that is preserved through saved instance state.

@ZacSweers
Copy link
Collaborator

What would an example of one of these look like? I'm inclined to lean toward what you mentioned at the end – decomposing your state and persisting them at whatever their correct granularity is.

@ZacSweers ZacSweers added the discussion Open discussions! label Jul 7, 2023
@ZacSweers
Copy link
Collaborator

@alexvanyo is this covered by #888 or still a different proposal?

@alexvanyo
Copy link
Contributor Author

I think this is still a different proposal than #888.

The use case would be an object that would ideally be retained, but for the event of process death, some parts should be saved and restored from instance state to be used instead of the original initialization call.

Maybe an example would be an object with a couple of ids that should survive process death, but the object also has some larger bits of data that would be good to retain?

The flow for rememberSaveable is:

  • when entering composition, restore from instance state if available
  • otherwise, run init
  • save to instance state when Android saved instance state is saved
  • when leaving composition, save to instance state

The flow for rememberRetained is:

  • when entering composition, restore from retained state if available
  • otherwise, run init
  • when leaving composition, save to retained

I think a combined flow for rememberRetainedSaveable could look something like:

  • when entering composition, restore from retained state if available
  • otherwise, restore from saveable state if available
  • otherwise, run init
  • save to instance state when Android saved instance state is saved
  • when leaving composition, save to instance state and save to retained

The retained value, if available, takes first precedence, but if the retained value isn't available, it falls back to whatever was stored in instance state first, before finally falling back to re-initializing the object entirely.

@ZacSweers
Copy link
Collaborator

Sounds good to me, PR would be welcome. I worry a little about the API surface area but can't think offhand of a solution that could make this more hierarchical and I suspect automatic isn't something we want here. @stagg and @chrisbanes may have better ideas

@chrisbanes
Copy link
Contributor

Yeah, I have the same worries about the API surface. I personally think this is better handled at the caller level, by using both rememberRetained and rememberSaveable as callers see appropriate.

@ZacSweers
Copy link
Collaborator

I've been looking a little more into this, and I think it's mechanically mostly doable but two issues/considerations arise

  1. We can't check if a value can be saved until performSave-time. This could result in some asymmetric state saving when restoring from positional keys
  2. What's the opinion of this? Is it rememberSaveable with retained caching (and thus everything going in must be saveable) or is it rememberRetained with saveable caching (and just quietly drops anything not saveable)

@ZacSweers
Copy link
Collaborator

I think if it's rememberSaveable with retained caching, this stays fairly simple. There is some divergence in what rememberRetained supports now that @chrisbanes added RememberObserver support, but I think it's fine as the rememberSaveable impl wouldn't allow those value types anyway.

@chrisbanes
Copy link
Contributor

My first thought would that rememberRetained with saveable saving on process death makes the most sense to me, as it uses the key benefits of both features.

@alexvanyo
Copy link
Contributor Author

With the exploration in #1305, I think rememberRetained would be equivalent to rememberRetainedSaveable with a Saver({ null }, { null}), which would make rememberRetainedSaveable "rememberRetained with saveable saving on process death"

and just quietly drops anything not saveable

I think a Saver argument would make that explicit. It would save to instance state whatever the retained value can be serialized to in compliance with Bundle restrictions

@stagg
Copy link
Collaborator

stagg commented Mar 25, 2024

rememberRetained with saveable caching

Think it's this, where saveable is an extension of retained. Requiring anyone wanting to opt-in to explicitly set the saver as @alexvanyo suggests. No default auto-saving option.

@ZacSweers
Copy link
Collaborator

I think rememberRetained would be equivalent to rememberRetainedSaveable with a Saver({ null }, { null})

Could we make it work that way in code? Basically have rememberRetained call through with that?

@chrisbanes
Copy link
Contributor

Or just add a Saver? param to rememberRetained?

@ZacSweers
Copy link
Collaborator

yeah that's what I was thinking too 👀

@alexvanyo
Copy link
Contributor Author

Updated #1305 to combine the backing implementation, and to see what it looks like to add the saver parameter to rememberRetained directly.

I think I initially prefer to have explictly separate rememberRetainedSaveable over just having rememberRetained with a saver argument, to match the setup with a plain remember and rememberSaveable, but I could be convinced otherwise.

@ZacSweers
Copy link
Collaborator

Shipped in 0.21.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Open discussions!
Projects
None yet
Development

No branches or pull requests

4 participants