J'ai essayé de mettre à niveau mon application Flutter pour utiliser Provider 4.0.1 aujourd'hui et le code suivant s'est écrasé lors de l'attribution d'une valeur à null.
Voici le code que je tente de convertir. J'ai seulement changé SingleChildCloneableWidget en SingleChildStatelessWidget qui a compilé OK.
Future<String> translate(BuildContext context, _term) async {
final String _languageCode = Provider.of<User>(context).language;
Je l'ai implémenté comme ceci:
Future<void> _setFixedLanguageStrings(BuildContext context) async {
User _user = Provider.of<User>(context);
_user.homeString = await translate(context, 'Home');
Le crash s'est produit sur cette ligne:
StreamController<User> _userController = StreamController<User>(); Stream<User> get user => _userController.stream;
Le 'langage' getter a été appelé sur null. Récepteur: nul
Cela fonctionnait bien avec Provider 3.0.3 mais je dois évidemment faire plus.
Mon code d'origine est issu de ce tutoriel .
edit: J'ai résolu ce problème en ajoutant lazy: false dans la méthode de création du fournisseur de flux, mais une autre erreur plus tard dans ce code.
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
];
qui a produit cette erreur:
Une exception s'est produite. _AssertionError ('package: provider / src / provider.dart': Échec de l'assertion: ligne 213 pos 7: 'context.owner.debugBuilding || listen == false || _debugIsInInheritedProviderUpdate': J'ai essayé d'écouter une valeur exposée avec le fournisseur, à partir de en dehors de l'arborescence des widgets.
Cela est probablement dû à un gestionnaire d'événements (comme onPressed d'un bouton) qui a appelé Provider.of sans passer
listen: false.Pour corriger, écrivez: Provider.of (context, listen: false);
Il n'est pas pris en charge car il peut reconstruire inutilement le widget associé au gestionnaire d'événements, lorsque l'arborescence du widget ne se soucie pas de la valeur. )
J'ai ajouté listen: false à la ligne ci-dessus qui semble avoir résolu ce problème, mais le fournisseur suivant que j'ai tenté d'utiliser a produit cette erreur:
J'ai essayé d'écouter une valeur exposée avec le fournisseur, depuis l'extérieur de l'arborescence des widgets.
Cela est probablement dû à un gestionnaire d'événements (comme onPressed d'un bouton) qui a appelé Provider.of sans passer
listen: false.Pour corriger, écrivez: Provider.of (context, listen: false);
Il n'est pas pris en charge car il peut reconstruire inutilement le widget associé au gestionnaire d'événements, lorsque l'arborescence du widget ne se soucie pas de la valeur. 'package: provider / src / provider.dart': Échec de l'assertion: ligne 213 pos 7: 'context.owner.debugBuilding || écoute == faux || _debugIsInInheritedProviderUpdate '
Dois-je maintenant accéder à chaque instance où j'appelle un fournisseur et ajoute listen: false ? J'ai besoin de quelqu'un pour expliquer ce qui a changé et pourquoi, car je suis assez nouveau chez Flutter et les documents sont rares pour Provider . Il y a de nombreuses fois où j'appelle Provider dans mon code et cette dernière erreur n'a pas renvoyé d'emplacement de code.
listen: false il toujours nécessaire alors que ce n'était pas avant ou ai-je manqué autre chose? Je commence à ajouter listen: false à chaque appel pour instancier une variable Provider et cela semble fonctionner, mais est-ce la bonne approche? Dois-je simplement ajouter listen: false à chaque appel à Provider.of et l'appeler un jour?
edit: L'erreur survient chaque fois que le fournisseur est appelé depuis l'extérieur de la partie visible de l'arborescence des widgets. Cette distinction est importante.
6 Réponses :
J'ai le même "problème", si j'ajoute listen: false partout où j'appelle le fournisseur le problème a disparu mais je ne sais pas si c'est la bonne solution ...?
Je me demande pourquoi listen: false n'est pas la valeur par défaut pour SingleChildStatelessWidget ?
il n'y a pas d'erreur avec listen: false, mais l'interface utilisateur ne se met pas à jour, donc quelque chose d'autre est nécessaire pour le faire fonctionner
listen : false appelé lorsque les données ne mettraient pas à jour quoi que ce soit dans l'interface utilisateur et devraient être utilisées, comme supprimer toutes les cartes d'un widget lorsque le bouton est cliqué.
Pour plus d'informations, lisez ce go_to_link
listen:true étant la valeur par défaut est logique.
Il ne spécifie pas dans un gestionnaire d'événements qui n'est pas logique. listen: false
De plus, 4.1.0 aura en quelque sorte une alternative plus courte à Provider. De:
context.read<T>() // Provider.of<T>(context, listen: false) context.watch<T>() // Provider.of<T>(context)
Dans mon cas, j'obtenais l'erreur suivante: -
context.read<T>() is same as Provider.of<T>(context, listen: false) And context.watch<T>() is same as Provider.of<T>(context)``` Ref :- https://github.com/rrousselGit/provider/issues/313
Comme vous pouvez le voir, cette solution est présente dans le message d'erreur lui-même.
Par conséquent, nous ne sommes pas censés utiliser le fournisseur avec les gestionnaires d'événements par défaut (listen: true).
Alternativement,
I/flutter ( 7206): Tried to listen to a value exposed with provider, from outside of the widget tree. I/flutter ( 7206): I/flutter ( 7206): This is likely caused by an event handler (like a button's onPressed) that called I/flutter ( 7206): Provider.of without passing `listen: false`. I/flutter ( 7206): I/flutter ( 7206): To fix, write: I/flutter ( 7206): Provider.of<AstroDetailsProvider>(context, listen: false); I/flutter ( 7206): I/flutter ( 7206): It is unsupported because may pointlessly rebuild the widget associated to the I/flutter ( 7206): event handler, when the widget tree doesn't care about the value.
Sur les gestionnaires d'événements comme onPressed , OnTap , onLongPressed etc., nous devons utiliser
Provider.of<T>(context,listen:true) //by default is listen:true
la raison étant qu'ils n'écouteront pas les changements de mise à jour, ils sont à la place responsables des changements.
alors que les widgets comme le texte, etc. sont responsables de l'affichage ... donc doivent être mis à jour à chaque changement effectué ... donc utilisez
Provider.of<T>(context,listen:false)
Si vous utilisez un fournisseur en dehors de la construction sans écouter: false
alors, bien sûr, vous ne pouvez pas écouter les changements car il n'a pas encore créé les widgets pour les changements. cela n'est pas une valeur par défaut car le fournisseur n'est pas censé utiliser en dehors de la construction car il est utilisé comme outil de gestion d'état et pour injecter des dépendances. Mais cependant, si vous utilisez en dehors de la construction, vous devez utiliser listen: false
Vous avez le même problème lors de la mise à jour. Le fait est, que faire si je peux ou non changer l'arborescence des widgets? Je recule.