More restoration documentation (#63438)

diff --git a/dev/snippets/config/templates/README.md b/dev/snippets/config/templates/README.md
index 6671b51..6f44955 100644
--- a/dev/snippets/config/templates/README.md
+++ b/dev/snippets/config/templates/README.md
@@ -87,6 +87,11 @@
   `stateful_widget` template, with the addition of the `TickerProviderStateMixin`
   class, enabling easy generation of animated samples.
 
+- [`stateful_widget_restoration`](stateful_widget_restoration.tmpl) : Similar to
+  the `stateful_widget` template, but the widget also imports `RestorationMixin`
+  and has a `restorationId` field which it uses to implement the `restorationId`
+  getter on the `State`.
+
 - [`stateless_widget`](stateless_widget.tmpl) : Identical to the
   `stateful_widget` template, except that the default code block is
   inserted as a method (which should be the `build` method) in a
diff --git a/dev/snippets/config/templates/stateful_widget_restoration.tmpl b/dev/snippets/config/templates/stateful_widget_restoration.tmpl
new file mode 100644
index 0000000..1aeb141
--- /dev/null
+++ b/dev/snippets/config/templates/stateful_widget_restoration.tmpl
@@ -0,0 +1,46 @@
+/// Flutter code sample for {{element}}
+
+{{description}}
+
+import 'package:flutter/material.dart';
+
+{{code-imports}}
+
+void main() => runApp(new MyApp());
+
+/// This is the main application widget.
+class MyApp extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return WidgetsApp(
+      title: 'Flutter Code Sample',
+      home: Center(
+        child: MyStatefulWidget(restorationId: 'main'),
+      ),
+      color: const Color(0xffffffff),
+    );
+  }
+}
+
+{{code-preamble}}
+
+/// This is the stateful widget that the main application instantiates.
+class MyStatefulWidget extends StatefulWidget {
+  MyStatefulWidget({Key key, this.restorationId}) : super(key: key);
+
+  final String restorationId;
+
+  @override
+  _MyStatefulWidgetState createState() => _MyStatefulWidgetState();
+}
+
+/// This is the private State class that goes with MyStatefulWidget.
+/// RestorationProperty objects can be used because of RestorationMixin.
+class _MyStatefulWidgetState extends State<MyStatefulWidget> with RestorationMixin {
+  // In this example, the restoration ID for the mixin is passed in through
+  // the [StatefulWidget]'s constructor.
+  @override
+  String get restorationId => widget.restorationId;
+
+{{code}}
+}
diff --git a/packages/flutter/lib/src/widgets/restoration_properties.dart b/packages/flutter/lib/src/widgets/restoration_properties.dart
index 3ac8e98..c90389e 100644
--- a/packages/flutter/lib/src/widgets/restoration_properties.dart
+++ b/packages/flutter/lib/src/widgets/restoration_properties.dart
@@ -19,6 +19,81 @@
 /// call [notifyListeners] from this method if the new value changes what
 /// [toPrimitives] returns.
 ///
+/// ## Using a RestorableValue
+///
+/// {@tool dartpad --template=stateful_widget_restoration}
+/// A [StatefulWidget] that has a restorable [int] property.
+///
+/// ```dart
+///   // The current value of the answer is stored in a [RestorableProperty].
+///   // During state restoration it is automatically restored to its old value.
+///   // If no restoration data is available to restore the answer from, it is
+///   // initialized to the specified default value, in this case 42.
+///   RestorableInt _answer = RestorableInt(42);
+///
+///   @override
+///   void restoreState(RestorationBucket oldBucket, bool initialRestore) {
+///     // All restorable properties must be registered with the mixin. After
+///     // registration, the answer either has its old value restored or is
+///     // initialized to its default value.
+///     registerForRestoration(_answer, 'answer');
+///   }
+///
+///   void _incrementAnswer() {
+///     setState(() {
+///       // The current value of the property can be accessed and modified via
+///       // the value getter and setter.
+///       _answer.value += 1;
+///     });
+///   }
+///
+///   @override
+///   void dispose() {
+///     // Properties must be disposed when no longer used.
+///     _answer.dispose();
+///     super.dispose();
+///   }
+///
+///   @override
+///   Widget build(BuildContext context) {
+///     return OutlinedButton(
+///       child: Text('${_answer.value}'),
+///       onPressed: _incrementAnswer,
+///     );
+///   }
+/// ```
+/// {@end-tool}
+///
+/// ## Creating a subclass
+///
+/// {@tool snippet}
+/// This example shows how to create a new `RestorableValue` subclass,
+/// in this case for the [Duration] class.
+///
+/// ```dart
+/// class RestorableDuration extends RestorableValue<Duration> {
+///   @override
+///   Duration createDefaultValue() => const Duration();
+///
+///   @override
+///   void didUpdateValue(Duration oldValue) {
+///     if (oldValue.inMicroseconds != value.inMicroseconds)
+///       notifyListeners();
+///   }
+///
+///   @override
+///   Duration fromPrimitives(Object data) {
+///     return Duration(microseconds: data as int);
+///   }
+///
+///   @override
+///   Object toPrimitives() {
+///     return value.inMicroseconds;
+///   }
+/// }
+/// ```
+/// {@end-tool}
+///
 /// See also:
 ///
 ///  * [RestorableProperty], which is the super class of this class.