Flutter Provider:如何监听类字段内部的类字段变化?

Posted

技术标签:

【中文标题】Flutter Provider:如何监听类字段内部的类字段变化?【英文标题】:Flutter Provider: How do I listen to a change of a class field inside a class field? 【发布时间】:2020-08-13 23:51:35 【问题描述】:

给定以下 Dart/Flutter 类结构:

import 'package:flutter/material.dart';

class A with ChangeNotifier 
  B _element1;
  B _element2;

  B get element1 => _element1;
  B get element2 => _element2;

  set element1(B value) 
    _element1 = value;
    notifyListeners();
  

  set element2(B value) 
    _element2 = value;
    notifyListeners();
  


class B 
  String x;
  String y;

我正在尝试收听A.element1.x 的变化,但问题是,B 类的setter 无法调用A 类的notifyListeners(),所以要么我在听A 并且不会注意到改变,或者我正在听 B,而我正在将上下文丢失给 A。

我在我的 Flutter 项目中使用 Provider 包。但我不确定,如果我误解了 Provider 包或 ChangeListeners 的概念。无论哪种方式,我都无法找到一个优雅的解决方案。

是否有可能从 A 类覆盖 B 类的 setter? 我显然可以为每个 element1 和 element2 字段(x,y)实现一个函数。但我猜这不是好的代码风格。

【问题讨论】:

有多种(一如既往;))方法可以解决这个问题:您可以在 B 类中注册一个回调,然后调用 A 类的函数,以便 A 类知道何时通知侦听器因为 B 的变化。或者使用流,由 B 公开并由 A 收听。但也许最好是查看 ProxyProvider 包。我没有这方面的经验,但我认为它可能适合您的用例。这是一个article。 你能帮我解决一下回调函数吗?我不熟悉回调函数。我查看了这篇文章,但找不到针对我的特定问题的解决方案。我还查看了文档,但不知道如何使用 ProxyProvider 来解决我的问题。 在下面发布了一个示例。这就是回调在 A 中调用 notifyListeners 的方式。我不确定这是否比仅在 A 上调用方法更好,然后在 B 上设置属性并直接调用 notifyListeners 【参考方案1】:

这是一个关于如何使用回调函数的示例。如果没有回调,A 将不会调用 notifyListeners 并且您的 Home 小部件不会重建。这是一个关于VoidCallback 是什么的简短视频:https://www.youtube.com/watch?v=fWlPwj1Pp7U

主函数和一个简单的Home 视图:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'a.dart';

void main() 
  runApp(
    ChangeNotifierProvider<A>(
      create: (context) => A(),
      child: MaterialApp(
        home: Home(),
      ),
    )
  );


class Home extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return Consumer<A>(
      builder: (context, model, child) 
        return Scaffold(
          body: Container(
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text('$model.element1.x'),
                  RaisedButton(
                    child: Text("Set x of element1."),
                    onPressed: () 
                      Provider.of<A>(context, listen: false).element1.setX = 'Set to new value';
                    ,
                  ),
                ],
              ),
            ),
          )
        );
      ,
    );
  

然后是A类:

import 'package:flutter/material.dart';
import 'package:tryout/b.dart';

class A extends ChangeNotifier 
  B _element1 = B();
  B _element2 = B();

  B get element1 => _element1;
  B get element2 => _element2;

  A() 
    _element1.callback = () => notifyListeners();
    _element2.callback = () => notifyListeners();
  

  set element1(B value) 
    _element1 = value;
    _element1.callback = () => notifyListeners();
    notifyListeners();
  

  set element2(B value) 
    _element2 = value;
    _element2.callback = () => notifyListeners();
    notifyListeners();
  

B 类:

import 'package:flutter/cupertino.dart';

class B 
  String x = "";
  String y = "";
  VoidCallback callback;

  B(
    this.callback
  );

  set setX(String newValueX) 
    x = newValueX;
    if(callback != null) callback();
  

  void setY(String newValueY) 
    y = newValueY;
    if(callback != null) callback();
  

【讨论】:

以上是关于Flutter Provider:如何监听类字段内部的类字段变化?的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter 中,是不是可以使用 Provider 创建监听函数

Flutter Provider:Firebase Auth StateChanges 被监听但状态没有改变

如何在 Flutter 中正确重用 Provider

flutter Provider状态管理

Flutter如何状态管理

如何在 Flutter 中将 textEditiing 控制器与 Provider 一起使用