Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter app crash after converting Provider 3 to 4

Tags:

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.

like image 319
markhorrocks Avatar asked Jan 04 '20 12:01

markhorrocks


1 Answers

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...?

like image 164
dukaric1991 Avatar answered Oct 14 '22 18:10

dukaric1991