1
import 'dart:async';
2

3
import 'package:collection/collection.dart';
4
import 'package:flutter/foundation.dart';
5
import 'package:flutter/widgets.dart';
6
import 'package:nested/nested.dart';
7
import 'package:flutter/rendering.dart';
8
import 'package:flutter/scheduler.dart';
9

10
import 'reassemble_handler.dart';
11

12
part 'inherited_provider.dart';
13
part 'deferred_inherited_provider.dart';
14

15
/// A provider that merges multiple providers into a single linear widget tree.
16
/// It is used to improve readability and reduce boilerplate code of having to
17
/// nest multiple layers of providers.
18
///
19
/// As such, we're going from:
20
///
21
/// ```dart
22
/// Provider<Something>(
23
///   create: (_) => Something(),
24
///   child: Provider<SomethingElse>(
25
///     create: (_) => SomethingElse(),
26
///     child: Provider<AnotherThing>(
27
///       create: (_) => AnotherThing(),
28
///       child: someWidget,
29
///     ),
30
///   ),
31
/// ),
32
/// ```
33
///
34
/// To:
35
///
36
/// ```dart
37
/// MultiProvider(
38
///   providers: [
39
///     Provider<Something>(create: (_) => Something()),
40
///     Provider<SomethingElse>(create: (_) => SomethingElse()),
41
///     Provider<AnotherThing>(create: (_) => AnotherThing()),
42
///   ],
43
///   child: someWidget,
44
/// )
45
/// ```
46
///
47
/// The widget tree representation of the two approaches are identical.
48
class MultiProvider extends Nested {
49
  /// Build a tree of providers from a list of [SingleChildWidget].
50
  ///
51
  /// The parameter `builder` is syntactic sugar for obtaining a [BuildContext] that can
52
  /// read the providers created.
53
  ///
54
  /// This code:
55
  ///
56
  /// ```dart
57
  /// MultiProvider(
58
  ///   providers: [
59
  ///     Provider<Something>(create: (_) => Something()),
60
  ///     Provider<SomethingElse>(create: (_) => SomethingElse()),
61
  ///     Provider<AnotherThing>(create: (_) => AnotherThing()),
62
  ///   ],
63
  ///   builder: (context, child) {
64
  ///     final something = context.watch<Something>();
65
  ///     return Text('$something');
66
  ///   },
67
  /// )
68
  /// ```
69
  ///
70
  /// is strictly equivalent to:
71
  ///
72
  /// ```dart
73
  /// MultiProvider(
74
  ///   providers: [
75
  ///     Provider<Something>(create: (_) => Something()),
76
  ///     Provider<SomethingElse>(create: (_) => SomethingElse()),
77
  ///     Provider<AnotherThing>(create: (_) => AnotherThing()),
78
  ///   ],
79
  ///   child: Builder(
80
  ///     builder: (context) {
81
  ///       final something = context.watch<Something>();
82
  ///       return Text('$something');
83
  ///     },
84
  ///   ),
85
  /// )
86
  /// ```
87
  ///
88
  /// For an explanation on the `child` parameter that `builder` receives,
89
  /// see the "Performance optimizations" section of [AnimatedBuilder].
90 3
  MultiProvider({
91
    Key key,
92
    @required List<SingleChildWidget> providers,
93
    Widget child,
94
    TransitionBuilder builder,
95 3
  })  : assert(providers != null),
96 3
        super(
97
          key: key,
98
          children: providers,
99
          child: builder != null
100 3
              ? Builder(
101 3
                  builder: (context) => builder(context, child),
102
                )
103
              : child,
104
        );
105
}
106

107
/// A [Provider] that manages the lifecycle of the value it provides by
108
/// delegating to a pair of [Create] and [Dispose].
109
///
110
/// It is usually used to avoid making a [StatefulWidget] for something trivial,
111
/// such as instantiating a BLoC.
112
///
113
/// [Provider] is the equivalent of a [State.initState] combined with
114
/// [State.dispose]. [Create] is called only once in [State.initState].
115
/// We cannot use [InheritedWidget] as it requires the value to be
116
/// constructor-initialized and final.
117
///
118
/// The following example instantiates a `Model` once, and disposes it when
119
/// [Provider] is removed from the tree.
120
///
121
/// ```dart
122
/// class Model {
123
///   void dispose() {}
124
/// }
125
///
126
/// class Stateless extends StatelessWidget {
127
///   @override
128
///   Widget build(BuildContext context) {
129
///     return Provider<Model>(
130
///       create: (context) =>  Model(),
131
///       dispose: (context, value) => value.dispose(),
132
///       child: ...,
133
///     );
134
///   }
135
/// }
136
/// ```
137
///
138
/// It is worth noting that the `create` callback is lazily called.
139
/// It is called the first time the value is read, instead of the first time
140
/// [Provider] is inserted in the widget tree.
141
///
142
/// This behavior can be disabled by passing `lazy: false` to [Provider].
143
///
144
/// ## Testing
145
///
146
/// When testing widgets that consumes providers, it is necessary to
147
/// add the proper providers in the widget tree above the tested widget.
148
///
149
/// A typical test may look like this:
150
///
151
/// ```dart
152
/// final foo = MockFoo();
153
///
154
/// await tester.pumpWidget(
155
///   Provider<Foo>.value(
156
///     value: foo,
157
///     child: TestedWidget(),
158
///   ),
159
/// );
160
/// ```
161
///
162
/// Note this example purposefully specified the object type, instead of having
163
/// it inferred.
164
/// Since we used a mocked class (typically using `mockito`), then we have to
165
/// downcast the mock to the type of the mocked class.
166
/// Otherwise, the type inference will resolve to `Provider<MockFoo>` instead of
167
/// `Provider<Foo>`, which will cause `Provider.of<Foo>` to fail.
168
class Provider<T> extends InheritedProvider<T> {
169
  /// Creates a value, store it, and expose it to its descendants.
170
  ///
171
  /// The value can be optionally disposed using [dispose] callback.
172
  /// This callback which will be called when [Provider] is unmounted from the
173
  /// widget tree.
174 3
  Provider({
175
    Key key,
176
    @required Create<T> create,
177
    Dispose<T> dispose,
178
    bool lazy,
179
    TransitionBuilder builder,
180
    Widget child,
181 3
  })  : assert(create != null),
182 3
        super(
183
          key: key,
184
          lazy: lazy,
185
          builder: builder,
186
          create: create,
187
          dispose: dispose,
188
          debugCheckInvalidValueType: kReleaseMode
189
              ? null
190 3
              : (T value) =>
191 3
                  Provider.debugCheckInvalidValueType?.call<T>(value),
192
          child: child,
193
        );
194

195
  /// Expose an existing value without disposing it.
196
  ///
197
  /// {@template provider.updateshouldnotify}
198
  /// `updateShouldNotify` can optionally be passed to avoid unnecessarily
199
  /// rebuilding dependents when [Provider] is rebuilt but `value` did not change.
200
  ///
201
  /// Defaults to `(previous, next) => previous != next`.
202
  /// See [InheritedWidget.updateShouldNotify] for more information.
203
  /// {@endtemplate}
204 3
  Provider.value({
205
    Key key,
206
    @required T value,
207
    UpdateShouldNotify<T> updateShouldNotify,
208
    TransitionBuilder builder,
209
    Widget child,
210 3
  })  : assert(() {
211 3
          Provider.debugCheckInvalidValueType?.call<T>(value);
212
          return true;
213 3
        }()),
214 3
        super.value(
215
          key: key,
216
          builder: builder,
217
          value: value,
218
          updateShouldNotify: updateShouldNotify,
219
          child: child,
220
        );
221

222
  /// Obtains the nearest [Provider<T>] up its widget tree and returns its
223
  /// value.
224
  ///
225
  /// If [listen] is `true`, later value changes will trigger a new
226
  /// [State.build] to widgets, and [State.didChangeDependencies] for
227
  /// [StatefulWidget].
228
  ///
229
  /// `listen: false` is necessary to be able to call `Provider.of` inside
230
  /// [State.initState] or the `create` method of providers like so:
231
  ///
232
  /// ```dart
233
  /// Provider(
234
  ///   create: (context) {
235
  ///     return Model(Provider.of<Something>(context, listen: false)),
236
  ///   },
237
  /// )
238
  /// ```
239 3
  static T of<T>(BuildContext context, {bool listen = true}) {
240 3
    assert(context != null);
241
    assert(
242 3
      context.owner.debugBuilding ||
243 3
          listen == false ||
244
          debugIsInInheritedProviderUpdate,
245
      '''
246
Tried to listen to a value exposed with provider, from outside of the widget tree.
247

248
This is likely caused by an event handler (like a button's onPressed) that called
249
Provider.of without passing `listen: false`.
250

251
To fix, write:
252
Provider.of<$T>(context, listen: false);
253

254
It is unsupported because may pointlessly rebuild the widget associated to the
255
event handler, when the widget tree doesn't care about the value.
256

257
The context used was: $context
258 3
''',
259
    );
260

261 3
    final inheritedElement = _inheritedElementOf<T>(context);
262

263
    if (listen) {
264 3
      context.dependOnInheritedElement(inheritedElement);
265
    }
266

267 3
    return inheritedElement.value;
268
  }
269

270 3
  static _InheritedProviderScopeElement<T> _inheritedElementOf<T>(
271
    BuildContext context,
272
  ) {
273 0
    assert(context != null, '''
274
Tried to call context.read/watch/select or similar on a `context` that is null.
275

276
This can happen if you used the context of a StatefulWidget and that
277
StatefulWidget was disposed.
278
''');
279
    assert(
280 3
      _debugIsSelecting == false,
281
      'Cannot call context.read/watch/select inside the callback of a context.select',
282
    );
283
    assert(
284 3
      T != dynamic,
285
      '''
286
Tried to call Provider.of<dynamic>. This is likely a mistake and is therefore
287
unsupported.
288

289
If you want to expose a variable that can be anything, consider changing
290
`dynamic` to `Object` instead.
291
''',
292
    );
293
    _InheritedProviderScopeElement<T> inheritedElement;
294

295 3
    if (context.widget is _InheritedProviderScope<T>) {
296
      // An InheritedProvider<T>'s update tries to obtain a parent provider of
297
      // the same type.
298 3
      context.visitAncestorElements((parent) {
299 3
        inheritedElement = parent.getElementForInheritedWidgetOfExactType<
300
            _InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>;
301
        return false;
302
      });
303
    } else {
304 3
      inheritedElement = context.getElementForInheritedWidgetOfExactType<
305
          _InheritedProviderScope<T>>() as _InheritedProviderScopeElement<T>;
306
    }
307

308
    if (inheritedElement == null) {
309 3
      throw ProviderNotFoundException(T, context.widget.runtimeType);
310
    }
311

312
    return inheritedElement;
313
  }
314

315
  /// A sanity check to prevent misuse of [Provider] when a variant should be
316
  /// used instead.
317
  ///
318
  /// By default, [debugCheckInvalidValueType] will throw if `value` is a
319
  /// [Listenable] or a [Stream]. In release mode, [debugCheckInvalidValueType]
320
  /// does nothing.
321
  ///
322
  /// You can override the default behavior by "decorating" the default function.\
323
  /// For example if you want to allow rxdart's `Subject` to work on [Provider], then
324
  /// you could do:
325
  ///
326
  /// ```dart
327
  /// void main() {
328
  ///  final previous = Provider.debugCheckInvalidValueType;
329
  ///  Provider.debugCheckInvalidValueType = <T>(value) {
330
  ///    if (value is Subject) return;
331
  ///    previous<T>(value);
332
  ///  };
333
  ///
334
  ///  // ...
335
  /// }
336
  /// ```
337
  ///
338
  /// This will allow `Subject`, but still allow [Stream]/[Listenable].
339
  ///
340
  /// Alternatively you can disable this check entirely by setting
341
  /// [debugCheckInvalidValueType] to `null`:
342
  ///
343
  /// ```dart
344
  /// void main() {
345
  ///   Provider.debugCheckInvalidValueType = null;
346
  ///   runApp(MyApp());
347
  /// }
348
  /// ```
349 3
  static void Function<T>(T value) debugCheckInvalidValueType = <T>(T value) {
350 3
    assert(() {
351 3
      if (value is Listenable || value is Stream) {
352 3
        throw FlutterError('''
353
Tried to use Provider with a subtype of Listenable/Stream ($T).
354

355
This is likely a mistake, as Provider will not automatically update dependents
356
when $T is updated. Instead, consider changing Provider for more specific
357
implementation that handles the update mechanism, such as:
358

359
- ListenableProvider
360
- ChangeNotifierProvider
361
- ValueListenableProvider
362
- StreamProvider
363

364
Alternatively, if you are making your own provider, consider using InheritedProvider.
365

366
If you think that this is not an error, you can disable this check by setting
367
Provider.debugCheckInvalidValueType to `null` in your main file:
368

369
```
370
void main() {
371
  Provider.debugCheckInvalidValueType = null;
372

373
  runApp(MyApp());
374
}
375
```
376 3
''');
377
      }
378
      return true;
379 3
    }());
380
  };
381
}
382

383
/// The error that will be thrown if [Provider.of] fails to find a [Provider]
384
/// as an ancestor of the [BuildContext] used.
385
class ProviderNotFoundException implements Exception {
386
  /// The type of the value being retrieved
387
  final Type valueType;
388

389
  /// The type of the Widget requesting the value
390
  final Type widgetType;
391

392
  /// Create a ProviderNotFound error with the type represented as a String.
393 3
  ProviderNotFoundException(
394
    this.valueType,
395
    this.widgetType,
396
  );
397

398 3
  @override
399
  String toString() {
400
    return '''
401 3
Error: Could not find the correct Provider<$valueType> above this $widgetType Widget
402

403
This likely happens because you used a `BuildContext` that does not include the provider
404
of your choice. There are a few common scenarios:
405

406
- The provider you are trying to read is in a different route.
407

408
  Providers are "scoped". So if you insert of provider inside a route, then
409
  other routes will not be able to access that provider.
410

411
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
412

413 3
  Make sure that $widgetType is under your MultiProvider/Provider<$valueType>.
414
  This usually happen when you are creating a provider and trying to read it immediately.
415

416
  For example, instead of:
417

418
  ```
419
  Widget build(BuildContext context) {
420
    return Provider<Example>(
421
      create: (_) => Example(),
422
      // Will throw a ProviderNotFoundError, because `context` is associated
423
      // to the widget that is the parent of `Provider<Example>`
424
      child: Text(context.watch<Example>()),
425
    ),
426
  }
427
  ```
428

429
  consider using `builder` like so:
430

431
  ```
432
  Widget build(BuildContext context) {
433
    return Provider<Example>(
434
      create: (_) => Example(),
435
      // we use `builder` to obtain a new `BuildContext` that has access to the provider
436
      builder: (context) {
437
        // No longer throws
438
        return Text(context.watch<Example>()),
439
      }
440
    ),
441
  }
442
  ```
443

444
If none of these solutions work, consider asking for help on StackOverflow:
445
https://stackoverflow.com/questions/tagged/flutter
446 3
''';
447
  }
448
}
449

450
/// Exposes the [read] method.
451
extension ReadContext on BuildContext {
452
  /// Obtain a value from the nearest ancestor provider of type [T].
453
  ///
454
  /// This method is the opposite of [watch].\
455
  /// It will _not_ make widget rebuild when the value changes and cannot be
456
  /// called inside [StatelessWidget.build]/[State.build].\
457
  /// On the other hand, it can be freely called _outside_ of these methods.
458
  ///
459
  /// If that is incompatible with your criteria, consider using `Provider.of(context, listen: false)`.\
460
  /// It does the same thing, but without these added restrictions (but unsafe).
461
  ///
462
  /// **DON'T** call [read] inside build if the value is used only for events:
463
  ///
464
  /// ```dart
465
  /// Widget build(BuildContext context) {
466
  ///   // counter is used only for the onPressed of RaisedButton
467
  ///   final counter = context.read<Counter>();
468
  ///
469
  ///   return RaisedButton(
470
  ///     onPressed: () => counter.increment(),
471
  ///   );
472
  /// }
473
  /// ```
474
  ///
475
  /// While this code is not bugged in itself, this is an anti-pattern.
476
  /// It could easily lead to bugs in the future after refactoring the widget
477
  /// to use `counter` for other things, but forget to change [read] into [watch].
478
  ///
479
  /// **CONSIDER** calling [read] inside event handlers:
480
  ///
481
  /// ```dart
482
  /// Widget build(BuildContext context) {
483
  ///   return RaisedButton(
484
  ///     onPressed: () {
485
  ///       // as performant as the previous previous solution, but resilient to refactoring
486
  ///       context.read<Counter>().increment(),
487
  ///     },
488
  ///   );
489
  /// }
490
  /// ```
491
  ///
492
  /// This has the same efficiency as the previous anti-pattern, but does not
493
  /// suffer from the drawback of being brittle.
494
  ///
495
  /// **DON'T** use [read] for creating widgets with a value that never changes
496
  ///
497
  /// ```dart
498
  /// Widget build(BuildContext context) {
499
  ///   // using read because we only use a value that never changes.
500
  ///   final model = context.read<Model>();
501
  ///
502
  ///   return Text('${model.valueThatNeverChanges}');
503
  /// }
504
  /// ```
505
  ///
506
  /// While the idea of not rebuilding the widget if something else changes is
507
  /// good, this should not be done with [read].
508
  /// Relying on [read] for optimisations is very brittle and dependent
509
  /// on an implementation detail.
510
  ///
511
  /// **CONSIDER** using [select] for filtering unwanted rebuilds
512
  ///
513
  /// ```dart
514
  /// Widget build(BuildContext context) {
515
  ///   // Using select to listen only to the value that used
516
  ///   final valueThatNeverChanges = context.select((Model model) => model.valueThatNeverChanges);
517
  ///
518
  ///   return Text('$valueThatNeverChanges');
519
  /// }
520
  /// ```
521
  ///
522
  /// While more verbose than [read], using [select] is a lot safer.
523
  /// It does not rely on implementation details on `Model`, and it makes
524
  /// impossible to have a bug where our UI does not refresh.
525
  ///
526
  /// ## Using [read] to simplify objects depending on other objects
527
  ///
528
  /// This method can be freely passed to objects, so that they can read providers
529
  /// without having a reference on a [BuildContext].
530
  ///
531
  /// For example, instead of:
532
  ///
533
  /// ```dart
534
  /// class Model {
535
  ///   Model(this.context);
536
  ///
537
  ///   final BuildContext context;
538
  ///
539
  ///   void method() {
540
  ///     print(Provider.of<Whatever>(context));
541
  ///   }
542
  /// }
543
  ///
544
  /// // ...
545
  ///
546
  /// Provider(
547
  ///   create: (context) => Model(context),
548
  ///   child: ...,
549
  /// )
550
  /// ```
551
  ///
552
  /// we will prefer to write:
553
  ///
554
  /// ```dart
555
  /// class Model {
556
  ///   Model(this.read);
557
  ///
558
  ///   // `Locator` is a typedef that matches the type of `read`
559
  ///   final Locator read;
560
  ///
561
  ///   void method() {
562
  ///     print(read<Whatever>());
563
  ///   }
564
  /// }
565
  ///
566
  /// // ...
567
  ///
568
  /// Provider(
569
  ///   create: (context) => Model(context.read),
570
  ///   child: ...,
571
  /// )
572
  /// ```
573
  ///
574
  /// Both snippets behaves the same. But in the second snippet, `Model` has no dependency
575
  /// on Flutter/[BuildContext]/provider.
576
  ///
577
  /// See also:
578
  ///
579
  /// - [WatchContext] and its `watch` method, similar to [read], but
580
  ///   will make the widget tree rebuild when the obtained value changes.
581
  /// - [Locator], a typedef to make it easier to pass [read] to objects.
582 3
  T read<T>() {
583
    assert(
584 3
        debugIsInInheritedProviderCreate ||
585 3
            (!debugDoingBuild && !debugIsInInheritedProviderUpdate),
586
        '''
587
Tried to use `context.read<$T>` inside either a `build` method or the `update` callback of a provider.
588

589
This is unsafe to do so. Instead, consider using `context.watch<$T>`.
590
If you used `context.read` voluntarily as a performance optimisation, the solution
591
is instead to use `context.select`.
592 3
''');
593 3
    return Provider.of<T>(this, listen: false);
594
  }
595
}
596

597
/// Exposes the [watch] method.
598
extension WatchContext on BuildContext {
599
  /// Obtain a value from the nearest ancestor provider of type [T], and subscribe
600
  /// to the provider.
601
  ///
602
  /// Calling this method is equivalent to calling:
603
  ///
604
  /// ```dart
605
  /// Provider.of<T>(context)
606
  /// ```
607
  ///
608
  /// This method is accessible only inside [StatelessWidget.build] and
609
  /// [State.build].\
610
  /// If you need need to use it outside of these methods, consider using [Provider.of]
611
  /// instead, which doesn't have this restriction.\
612
  /// The only exception to this rule is Providers's `update` method.
613
  ///
614
  /// See also:
615
  ///
616
  /// - [ReadContext] and its `read` method, similar to [watch], but doesn't make
617
  ///   widgets rebuild if the value obtained changes.
618 3
  T watch<T>() {
619
    assert(
620 3
        widget is LayoutBuilder ||
621 3
            widget is SliverWithKeepAliveWidget ||
622 3
            debugDoingBuild ||
623
            debugIsInInheritedProviderUpdate,
624
        '''
625
Tried to use `context.watch<$T>` outside of the `build` method or `update` callback of a provider.
626

627
This is likely a mistake, as it doesn't make sense to rebuild a widget when the value
628
obtained changes, if that value is not used to build other widgets.
629

630
Consider using `context.read<$T> instead.
631 3
''');
632 3
    return Provider.of<T>(this);
633
  }
634
}
635

636
/// A generic function that can be called to read providers, without having a
637
/// reference on [BuildContext].
638
///
639
/// It is typically a reference to the `read` [BuildContext] extension:
640
///
641
/// ```dart
642
/// BuildContext context;
643
/// Locator locator = context.read;
644
/// ```
645
///
646
/// This function
647
typedef Locator = T Function<T>();

Read our documentation on viewing source code .

Loading