提供者 NotifyListeners 不更新消费者

Posted

技术标签:

【中文标题】提供者 NotifyListeners 不更新消费者【英文标题】:Provider NotifyListeners not updating consumers 【发布时间】:2021-03-17 16:47:30 【问题描述】:

我是 Flutter 的新手,真的非常想使用 provider 来传递数据,但我就是无法让它工作。我想我一切都设置好了,但由于某种原因,当我通知听众时,我的应用程序没有刷新。我要做的就是更新个人资料图片。我从 firebase 中的图片开始(工作正常)。然后我让用户可以选择用相机或照片更新他们的照片。当他们选择一张新照片时,消费者不会像我期望的那样更新。有人可以告诉我我是否做错了什么或者我如何能够做到这一点?

首先,这是我的主要内容:

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MultiProvider(
      providers: [
        ChangeNotifierProvider<Storage>(create: (context) => Storage()),
        StreamProvider<Uid>.value(value: AuthService().user),   
      ],
      child: MaterialApp(   ....

然后这里是更新我从图像选择器类调用的照片 URL 的类和方法。我正在传递上下文,因此我可以弹出该图像选择器视图并在完成后返回个人资料页面。

class Storage with ChangeNotifier 
  String userPhotoUrl;
  void uploadImage(PickedFile _imageFile, BuildContext context) async 

      ....     //some other code here

      try 
        var snapshot =
            await _storage.ref().child('/profileImages/$_userId').putFile(file);

        await snapshot.ref.getDownloadURL().then((value) 
          userPhotoUrl = value;
          notifyListeners();
          print(userPhotoUrl); //I know the code is working because it prints here
          Navigator.pop(context); 
        );
       catch (e) 
        print(e);
     
      
   


这是我正在尝试更新的个人资料页面。它只是没有得到更新的值。

class Profile extends StatefulWidget 
  Profile(Key key) : super(key: key);

  @override
  _ProfileState createState() => _ProfileState();


/// This is the private State class that goes with MyStatefulWidget.
class _ProfileState extends State<Profile> with TickerProviderStateMixin 


     String imageUrl;  //firebase pic to start - works fine

@override
  Widget build(BuildContext context) 

                       ....//some more widget tree

                 Consumer<Storage>(   
                  builder: (context, storage, widget) =>
                     CircularProfileAvatar(            //never updates. userPhotoURL always null
                        storage.userPhotoUrl ?? imageUrl, //always uses imageUrl,
                        elevation: 20,
                        borderColor: Colors.white70,
                        borderWidth: 1,
                        radius: 50,
                         ),
                     ),

知道为什么它不起作用吗?我认为这应该很容易,但提供者仍在暗指我......

【问题讨论】:

class Storage with ChangeNotifier 应该是 class Storage extends ChangeNotifier 你是如何从视图中触发uploadImage() @Toheeb,感谢您的建议,但扩展 ChangeNotifier 并没有帮助。我使用'with'是因为我最初扩展了存储,然后删除了扩展并忘记了更改。 uploadImage() 是从 ImageGrabber 类中调用的。所以流程是,用户在个人资料页面上,然后单击一个按钮,将他们带到 ImageGrabber 页面以选择相机或照片。然后有一个上传按钮,它从 Storage 调用 uploadImage()。我正在传递上下文以弹出 ImageGrabber 视图并返回到 Profile。 您是否在做类似var storageNotifier = Provider.of&lt;Storage&gt;(context); 的事情,然后像storageNotifier.uploadImage() 这样触发上传? 不,我使用 provider 只是为了获取 imageUrl,然后当 Provider.of 不起作用时,我转而尝试 Consumer,但同样的事情。我正在使用来自不同类的按钮来调用 uploadImage()。 【参考方案1】:

你使用了错误的方法来解决你需要做一些这样的问题

Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => ChangeNotifierProvider<Storage>(
            create: (context) => Storage(),
            child: ImageGrabberScreen(),
    ),
  ),
);

导航到您要使用Consumer() 小部件的屏幕时

通过使用 Provider 或 MultipleProvider 作为父级,你告诉颤振你想使用 StreamBuilder()widget 但从你的工作中我看到你正在使用 Consumer() 小部件

还可以尝试执行以下操作来触发您的功能

Widget build(BuildContext context) 
 var storageNotifier = Provider.of<Storage>(context);
  ///In your button you can then do storageNotifier.uploadImage();

如果您没有用于触发此事件的任何形式的按钮,最好使用FutureBuilder 解决此类问题

Future<String> uploadImage() async 

  ....     //some other code here

    var snapshot =
        await _storage.ref().child('/profileImages/$_userId').putFile(file);

  return  await snapshot.ref.getDownloadURL();
  

然后在小部件树的某个地方执行此操作

FutureBuilder(
  future: uploadImage(),
  builder: (_,snapshot)
    if(snapshot.hasData)
       return CircularProfileAvatar(snapshot.data);
    else
     return CircularProfileAvatar(imageUrl);
    
  )
 ...widget tree continues

【讨论】:

这并没有改变结果。它仍然像以前一样工作。不过感谢您的建议。还有什么? 理想情况下,您应该使用FutureBuilder 来解决这个问题,我会更新我的答案。 我喜欢 FutureBuilder 的建议,初始按钮首先将我带到不同的视图/类 (ImageGrabber)。在 imageGrabber 中,还有另一个按钮可以使用触发 uploadImage() 的图片。那么你会建议我如何使用 FutureBuilder 来完成这项工作?

以上是关于提供者 NotifyListeners 不更新消费者的主要内容,如果未能解决你的问题,请参考以下文章

消费者未使用 notifyListeners() 进行更新

Flutter:`notifyListeners`不更新列表

Provider 调用 notifyListeners() 时 Flutter View 不更新视图

NotifyListeners 未更新 Flutter Widget

颤振 notifyListeners 似乎不起作用

在 deactivate() 中调用 notifyListeners() 会导致错误 - Flutter