Skip to content

Restoration Framework - #60375

Merged
goderbauer merged 47 commits into
flutter:masterfrom
goderbauer:restoration-framework
Jul 28, 2020
Merged

goderbauer merged 47 commits into
flutter:masterfrom
goderbauer:restoration-framework

Conversation

@goderbauer

@goderbauer goderbauer commented Jun 26, 2020 •

Copy link
Copy Markdown
Member

Marked as WIP because I am still working on the tests (I decided to refactor the original testing framework for state restoration a little more to make it easier to use).

Description

Implements https://flutter.dev/go/state-restoration-design.

This PR introduces the basic framework for state restoration in Flutter as outlined in the document above.

In the service layer, the following concepts are introduced:

  • RestorationManager, which synchronizes the restoration data between engine and framework.
  • RestorationBucket, which stores the restoration data in a tree.
  • RestorationId, which identifies a piece of restoration data uniquely within a RestorationBucket.

In the widget layer, the following concepts are introduced. This is what most developers will presumably work with to make their apps restorable.

  • RestorationMixin, which is mixed into a State object to make certain values in the state restorable.
  • RestorableProperty, which holds the data within a State object that need to be restorable.
  • Many subclasses of RestorableProperty for storing specific data types, e.g. RestorableInt, RestorableString, etc.
  • Various RestorationScope widgets to create new name spaces for RestorationIds in the widget tree.

Related Issues

#6827

Tests

I added the following tests:

  • Tests for newly introduced concepts in the service layer: RestorationManager, RestorationBucket, RestorationId and friends.
  • WIP: tests for the widget layer.

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]). This will ensure a smooth and quick review process.

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read Handling breaking changes.

@fluttergithubbot fluttergithubbot added framework flutter/packages/flutter repository. See also f: labels. work in progress; do not review labels Jun 26, 2020

@jonahwilliams jonahwilliams left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is super cool! Was just reading through to see how you were doing it and found some minor typos.

Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
@goderbauer

Copy link
Copy Markdown
Member Author

Tests for newly introduced concepts in the service layer (RestorationManager, RestorationBucket, RestorationId and friends) have been added. Coming up next: tests for the widget layer.

Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/widgets/restoration.dart Outdated
Comment thread packages/flutter/lib/src/widgets/restoration.dart Outdated
@goderbauer
goderbauer force-pushed the restoration-framework branch 4 times, most recently from ac736ba to 99efc80 Compare July 8, 2020 20:35
@goderbauer
goderbauer force-pushed the restoration-framework branch from 99efc80 to 62016d2 Compare July 9, 2020 18:32
@goderbauer
goderbauer marked this pull request as ready for review July 9, 2020 20:40
@fluttergithubbot fluttergithubbot added the a: tests "flutter test", flutter_test, or one of our tests label Jul 9, 2020
@goderbauer

Copy link
Copy Markdown
Member Author

This PR is now complete and ready for review, PTAL @gspencergoog and @Hixie.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: document that the object has to be cast-able to a Map<dynamic, dynamic>, otherwise will throw?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is any kind of map this actually will not throw until you attempt to access something. The example below does not throw unless you uncomment the print.

void main() {
  var intMap = <int, int>{2: 3};
  var stringMap = intMap.cast<String, String>();
 // print(stringMap.keys.first);
}

This also means the type checks and casts are incurred on every access, instead of once at the beginning. If you wanted something that threw eagerly, you could use Map.from instead

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh. Should we really be exposing this method then?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this again, I don't need this method at all. I am removing it.

Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hashing the runtime type seems strange - why are we doing that? Can you document it here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed that, I think this was left-over from copying this from elsewhere.

Comment thread packages/flutter/lib/src/services/restoration.dart Outdated
Comment thread packages/flutter/lib/src/services/restoration.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be in an assert in the ctor body?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, changed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this required?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really want people to provide this, otherwise they will get bad error messages in case of duplicated IDs.

Comment on lines 563 to 564

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This would be more efficient as:

if (_parent != null) {
  parent._dropChild(this);
  parent_ = null;
}

right?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have this method and dispose?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(IOW why not just fold it into dispose)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dispose and decommission are different. Decommission is a notification that this entire bucket subtree is getting replaced with a new bucket hierarchy. All the children are informed about this so the owner of them can dispose them and claim a new bucket.

Dispose simply removes the information of this bucket from the hierarchy. The child bucket continue to have a live of their own and the owners of those child buckets may get them adopted by other parents.

Decommission = notification down the tree to stop using any bucket in this hierarchy.
dispose = delete the data from this bucket, child buckets can continue to live if they want.

@goderbauer
goderbauer force-pushed the restoration-framework branch from 6956d31 to f2e1d5f Compare July 28, 2020 16:22
@goderbauer
goderbauer merged commit 175e5c9 into flutter:master Jul 28, 2020
@goderbauer
goderbauer deleted the restoration-framework branch July 28, 2020 17:16
@gspencergoog

Copy link
Copy Markdown
Contributor

Whoohoo! 🥳🥳🥳

Pragya007 pushed a commit to Pragya007/flutter that referenced this pull request Aug 11, 2020
* state restoration

* added example

* typos and analyzer

* whitespace

* more typos

* remove unnecessary import

* whitespace

* fix sample code

* tests for restorationmanager and restorationid

* ++

* typo

* tests for bucket, part1

* rename tests

* more tests

* finished tests for service layer

* remove wrong todo

* ++

* review comments

* tests for Unmanaged and regular scope

* RootRestorationScope tests

* typo

* whitespace

* testing framework

* tests for properties

* last set of tests

* analyzer

* typo

* dan review

* whitespace

* ++

* refactor finalizers

* ++

* ++

* dispose guard

* ++

* ++

* dan review

* add manager assert

* ++

* analyzer

* greg review

* fix typo

* Ian & John review

* ian review

* RestorationID -> String

* revert comment

* Make primitives non-nullable in prep for NNBD
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
* state restoration

* added example

* typos and analyzer

* whitespace

* more typos

* remove unnecessary import

* whitespace

* fix sample code

* tests for restorationmanager and restorationid

* ++

* typo

* tests for bucket, part1

* rename tests

* more tests

* finished tests for service layer

* remove wrong todo

* ++

* review comments

* tests for Unmanaged and regular scope

* RootRestorationScope tests

* typo

* whitespace

* testing framework

* tests for properties

* last set of tests

* analyzer

* typo

* dan review

* whitespace

* ++

* refactor finalizers

* ++

* ++

* dispose guard

* ++

* ++

* dan review

* add manager assert

* ++

* analyzer

* greg review

* fix typo

* Ian & John review

* ian review

* RestorationID -> String

* revert comment

* Make primitives non-nullable in prep for NNBD
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Jul 30, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

a: tests "flutter test", flutter_test, or one of our tests framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants