diff --git a/packages/flutter/lib/src/widgets/page_storage.dart b/packages/flutter/lib/src/widgets/page_storage.dart index 90cb7afbce..a9acc70e1b 100644 --- a/packages/flutter/lib/src/widgets/page_storage.dart +++ b/packages/flutter/lib/src/widgets/page_storage.dart @@ -39,21 +39,19 @@ class PageStorageKey extends ValueKey { } class _StorageEntryIdentifier { - _StorageEntryIdentifier(this.clientType, this.keys) { - assert(clientType != null); + _StorageEntryIdentifier(this.keys) { assert(keys != null); } - final Type clientType; final List> keys; + bool get isNotEmpty => keys.isNotEmpty; + @override bool operator ==(dynamic other) { if (other.runtimeType != runtimeType) return false; final _StorageEntryIdentifier typedOther = other; - if (clientType != typedOther.clientType || keys.length != typedOther.keys.length) - return false; for (int index = 0; index < keys.length; index += 1) { if (keys[index] != typedOther.keys[index]) return false; @@ -62,11 +60,11 @@ class _StorageEntryIdentifier { } @override - int get hashCode => hashValues(clientType, hashList(keys)); + int get hashCode => hashList(keys); @override String toString() { - return 'StorageEntryIdentifier($clientType, ${keys?.join(":")})'; + return 'StorageEntryIdentifier(${keys?.join(":")})'; } } @@ -94,31 +92,45 @@ class PageStorageBucket { } _StorageEntryIdentifier _computeIdentifier(BuildContext context) { - return new _StorageEntryIdentifier(context.widget.runtimeType, _allKeys(context)); + return new _StorageEntryIdentifier(_allKeys(context)); } Map _storage; - /// Write the given data into this page storage bucket using an identifier - /// computed from the given context. The identifier is based on the keys - /// found in the path from context to the root of the widget tree for this - /// page. Keys are collected until the widget tree's root is reached or - /// a GlobalKey is found. + /// Write the given data into this page storage bucket using the + /// specified identifier or an identifier computed from the given context. + /// The computed identifier is based on the [PageStorageKey]s + /// found in the path from context to the [PageStorage] widget that + /// owns this page storage bucket. /// - /// An explicit identifier can be used in cases where the list of keys - /// is not stable. For example if the path concludes with a GlobalKey - /// that's created by a stateful widget, if the stateful widget is - /// recreated when it's exposed by [Navigator.pop], then its storage - /// identifier will change. + /// If an explicit identifier is not provided and no [PageStorageKey]s + /// are found, then the `data` is not saved. void writeState(BuildContext context, dynamic data, { Object identifier }) { _storage ??= {}; - _storage[identifier ?? _computeIdentifier(context)] = data; + if (identifier != null) { + _storage[identifier] = data; + } else { + final _StorageEntryIdentifier contextIdentifier = _computeIdentifier(context); + if (contextIdentifier.isNotEmpty) + _storage[contextIdentifier] = data; + } } - /// Read given data from into this page storage bucket using an identifier - /// computed from the given context. More about [identifier] in [writeState]. + /// Read given data from into this page storage bucket using the specified + /// identifier or an identifier computed from the given context. + /// The computed identifier is based on the [PageStorageKey]s + /// found in the path from context to the [PageStorage] widget that + /// owns this page storage bucket. + /// + /// If an explicit identifier is not provided and no [PageStorageKey]s + /// are found, then null is returned. dynamic readState(BuildContext context, { Object identifier }) { - return _storage != null ? _storage[identifier ?? _computeIdentifier(context)] : null; + if (_storage == null) + return null; + if (identifier != null) + return _storage[identifier]; + final _StorageEntryIdentifier contextIdentifier = _computeIdentifier(context); + return contextIdentifier.isNotEmpty ? _storage[contextIdentifier] : null; } } diff --git a/packages/flutter/test/widgets/page_storage_test.dart b/packages/flutter/test/widgets/page_storage_test.dart index d52e173cda..fbe0d08881 100644 --- a/packages/flutter/test/widgets/page_storage_test.dart +++ b/packages/flutter/test/widgets/page_storage_test.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; void main() { testWidgets('PageStorage read and write', (WidgetTester tester) async { - final Key builderKey = const Key('builderKey'); + final Key builderKey = const PageStorageKey('builderKey'); StateSetter setState; int storedValue = 0; diff --git a/packages/flutter/test/widgets/page_view_test.dart b/packages/flutter/test/widgets/page_view_test.dart index 0089e2dd2c..07f4ea8922 100644 --- a/packages/flutter/test/widgets/page_view_test.dart +++ b/packages/flutter/test/widgets/page_view_test.dart @@ -407,6 +407,7 @@ void main() { new PageStorage( bucket: bucket, child: new PageView( + key: const PageStorageKey('PageView'), controller: controller, children: [ const Placeholder(), @@ -431,6 +432,7 @@ void main() { new PageStorage( bucket: bucket, child: new PageView( + key: const PageStorageKey('PageView'), controller: controller, children: [ const Placeholder(), @@ -447,7 +449,7 @@ void main() { new PageStorage( bucket: bucket, child: new PageView( - key: const Key('Check it again against your list and see consistency!'), + key: const PageStorageKey('Check it again against your list and see consistency!'), controller: controller2, children: [ const Placeholder(), diff --git a/packages/flutter/test/widgets/remember_scroll_position_test.dart b/packages/flutter/test/widgets/remember_scroll_position_test.dart index 393addb450..58f039c6ab 100644 --- a/packages/flutter/test/widgets/remember_scroll_position_test.dart +++ b/packages/flutter/test/widgets/remember_scroll_position_test.dart @@ -18,6 +18,7 @@ class ThePositiveNumbers extends StatelessWidget { @override Widget build(BuildContext context) { return new ListView.builder( + key: const PageStorageKey('ThePositiveNumbers'), itemExtent: 100.0, controller: _controller, itemBuilder: (BuildContext context, int index) { diff --git a/packages/flutter/test/widgets/scroll_controller_test.dart b/packages/flutter/test/widgets/scroll_controller_test.dart index 5ae0e4d5eb..388e347707 100644 --- a/packages/flutter/test/widgets/scroll_controller_test.dart +++ b/packages/flutter/test/widgets/scroll_controller_test.dart @@ -266,12 +266,15 @@ void main() { Widget buildFrame(ScrollController controller) { return new PageStorage( bucket: bucket, - child: new ListView( - key: new UniqueKey(), // it's a different ListView every time - controller: controller, - children: new List.generate(50, (int index) { - return new Container(height: 100.0, child: new Text('Item $index')); - }).toList(), + child: new KeyedSubtree( + key: const PageStorageKey('ListView'), + child: new ListView( + key: new UniqueKey(), // it's a different ListView every time + controller: controller, + children: new List.generate(50, (int index) { + return new Container(height: 100.0, child: new Text('Item $index')); + }).toList(), + ), ), ); }