Finish the migration from scoped_model to provider

After this change, we’re managing Counter’s lifecycle with ChangeNotifierProvider.

This removes the periodic Timer. Not only does that simplify the example and makes it closer to the original, it also prevents a leaking timer (though, in this case, it’s not an issue, since the timer is needed for the whole duration of the app). I experimented with a more robust approach (having or injecting a Timer/StreamController into the Counter, and disposing of it there) but that seemed overly complex for such a simple example. This whole problem will get significantly easier with https://github.com/rrousselGit/provider/issues/46, at which point I could reintroduce this. I will also think about a more complex Provider example, something like the venerable `bloc_complex`, with infinite-scrolling pagination and all that.
pull/83/head
Filip Hracek 5 years ago
parent 31edec5378
commit 7bae186046

@ -1,31 +1,29 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
// Initialize the model. Can be done outside a widget, like here.
var counter = Counter();
// Setup a delayed interaction with the model (increment each 5 seconds),
// outside of the Flutter widget tree.
Timer.periodic(
const Duration(seconds: 5),
(timer) => counter.increment(),
);
// Now we're ready to run the app...
runApp(
// ... and provide the model to all widgets within.
ChangeNotifierProvider<Counter>.value(
notifier: counter,
// Provide the model to all widgets within the app. We're using
// ChangeNotifierProvider because that's a simple way to rebuild
// widgets when a model changes. We could also just use
// Provider, but then we would have to listen to Counter ourselves.
//
// Read Provider's docs to learn about all the available providers.
ChangeNotifierProvider(
// Initialize the model in the builder. That way, Provider
// can own Counter's lifecycle, making sure to call `dispose`
// when not needed anymore.
builder: (context) => Counter(),
child: MyApp(),
),
);
}
/// Simplest possible model, with just one field.
class Counter extends ChangeNotifier {
///
/// [ChangeNotifier] is a class in `flutter:foundation`. [Counter] does
/// _not_ depend on Provider.
class Counter with ChangeNotifier {
int value = 0;
void increment() {
@ -59,7 +57,7 @@ class MyHomePage extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
// ScopedModelDescendant looks for an ancestor ScopedModel widget
// Consumer looks for an ancestor Provider widget
// and retrieves its model (Counter, in this case).
// Then it uses that model to build widgets, and will trigger
// rebuilds if the model is updated.
@ -73,11 +71,15 @@ class MyHomePage extends StatelessWidget {
),
),
floatingActionButton: FloatingActionButton(
// ScopedModel.of is another way to access the model object held
// by an ancestor ScopedModel. By default, it just returns
// the current model and doesn't automatically trigger rebuilds.
// Since this button always looks the same, though, no rebuilds
// are needed.
// Provider.of is another way to access the model object held
// by an ancestor Provider. By default, even this listens to
// changes in the model, and rebuilds the whole encompassing widget
// when notified.
//
// By using `listen: false` below, we are disabling that
// behavior. We are only calling a function here, and so we don't care
// about the current value. Without `listen: false`, we'd be rebuilding
// the whole MyHomePage whenever Counter notifies listeners.
onPressed: () =>
Provider.of<Counter>(context, listen: false).increment(),
tooltip: 'Increment',

Loading…
Cancel
Save