Flutter app crash after converting Provider 3 to 4

flutter

I tried to upgrade my Flutter app to use Provider 4.0.1 today and the following code crashed on assigning a value to null.

Here is the code I am attempting to convert. I only changed SingleChildCloneableWidget to SingleChildStatelessWidget which compiled OK.

import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';

List<SingleChildStatelessWidget> providers = [
  ...independentServices,
  ...dependentServices,
  ...uiConsumableProviders
];

List<SingleChildStatelessWidget> independentServices = [
  Provider.value(value: Api()),
  Provider.value(value: Tbl()),
  Provider.value(value: Bill()),
  Provider.value(value: Sale()),
  Provider.value(value: Category()),
  Provider.value(value: Menu()),
];

List<SingleChildStatelessWidget> dependentServices = [
  ProxyProvider<Api, AuthenticationService>(
    update: (context, api, authenticationService) => AuthenticationService(api: api),
  ),
];

List<SingleChildStatelessWidget> uiConsumableProviders = [
  StreamProvider<User>(
    create: (context) => Provider.of<AuthenticationService>(context, listen: false).user,
  ),
    lazy: false
];

I implemented it like this:

StreamController<User> _userController = StreamController<User>();
Stream<User> get user => _userController.stream;

The crash occurred at this line:

Future<void> _setFixedLanguageStrings(BuildContext context) async {

 User _user = Provider.of<User>(context);
 
 _user.homeString = await translate(context, 'Home');

The getter 'language' was called on null. Receiver: null

This was working fine with Provider 3.0.3 but obviously I need to do more.

My original code came from this tutorial.

edit: I fixed that problem by adding lazy: false in the stream provider create method but then another error later in this code.

Future<String> translate(BuildContext context, _term) async {

  final String _languageCode = Provider.of<User>(context).language;

which produced this error:

Exception has occurred.
_AssertionError ('package:provider/src/provider.dart': Failed assertion: line 213 pos 7: 'context.owner.debugBuilding || listen ==
false || _debugIsInInheritedProviderUpdate': Tried to listen to a
value exposed with provider, from outside of the widget tree.

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

To fix, write: Provider.of(context, listen: false);

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

I added listen: false to the line above which seems to have fixed that problem, however the next provider I attempted to use produced this error:

Tried to listen to a value exposed with provider, from outside of the
widget tree.

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

To fix, write: Provider.of(context, listen: false);

It is unsupported because may pointlessly rebuild the widget
associated to the event handler, when the widget tree doesn't care
about the value. 'package:provider/src/provider.dart': Failed
assertion: line 213 pos 7: 'context.owner.debugBuilding || listen ==
false || _debugIsInInheritedProviderUpdate'

Should I now go to every instance where I call a provider and add listen: false? I need somebody to explain what has changed and why as I am fairly new at Flutter and the docs are sparse for Provider. There are many times where I call Provider in my code and this last error did not return a code location.

Is listen: false now always required when it wasn't before or have I missed something else? I am starting to add listen: false to every call to instantiate a Provider variable and it appears to be working but is this the correct approach? Should I just add listen: false to every call to Provider.of and call it a day?

edit: The error arises whenever the provider is called from outside the visible part of the widget tree. This distinction is important.

Best Answer

I have the same "problem", if i add listen: false everywhere i call Provider the problem is gone but i dont know if thats the right solution...?

Related Topic