Flutter - 如何使用 ChangeNotifier 正确获取数据

Flutter - how to fetch data correctly with ChangeNotifier

我想在应用运行后获取整个应用的天气统计数据。

我的ChangeNotifier:

class WeatherStatsNotifier extends ChangeNotifier {
  WeatherService weatherService;
  Future<WeatherStats> _stats;

  WeatherStatsNotifier({this.weatherService});

  Future<WeatherStats> get stats => _stats;

  void refreshStats() {
    _stats = weatherService.fetchWeatherStats();
    notifyListeners(); // it works when I remove this line
  }
}

我的主文件:

final WeatherService weatherService = new WeatherService();

void main() => runApp(ChangeNotifierProvider(
    create: (context) => WeatherStatsNotifier(weatherService: weatherService),
    child: App()));

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  @override
  void didChangeDependencies() {
    Provider.of<WeatherStatsNotifier>(context, listen: false).refreshStats();
    super.didChangeDependencies();
  }

  //... build method
}

还有更深的地方:

@override
  Widget build(BuildContext context) {
    return Consumer<WeatherStatsNotifier>(
      builder: (context, value, child) {
        return FutureBuilder<WeatherStats>(
          future: value.stats,
          builder: (context, snapshot) {
            return _buildForSnapshot(snapshot);
          },
        );
      },
    );
  }

最后我得到一个错误:

======== Exception caught by widgets library =======================================================
The following assertion was thrown building ChangeNotifierProvider<WeatherStatsNotifier>(message: 'package:flutter/src/widgets/framework.dart': Failed assertion: line 4195 pos 12: '!_dirty': is not true.\nSee also: https://flutter.dev/docs/testing/errors, dirty, renderObject: RenderErrorBox#c84e8 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE DETACHED):
'package:flutter/src/widgets/framework.dart': Failed assertion: line 4195 pos 12: '!_dirty': is not true.

如何正确操作?我可以在 initStatedidChangeDependencies 中使用 context 吗?

这是我如何使用值通知程序获取数据的最佳实践

  1. 使用类型数据
  2. 定义值通知器
ex:
class _AppState extends State<App> {
ValueNotifier<String> _weatherStatsNotifier;
  1. 添加到默认值的初始状态(以处理空值)是的,如果需要,您也可以使用上下文
@override
void initState() {
super.initState();
_weatherStatsNotifier = ValueNotifier(emtpyString);
  1. 然后,如果数据已经获取,则更改值
_weatherStatsNotifier.value = weatherService;

或者在我的例子中,我通常使用来自监听状态的值通知器

_weatherBloc.listen(
        (state) {
          if (state is weatherLoadedState) {
            _weatherStatsNotifier.value = state.weather;
          }
        },
      );

4.Use 作为数据 ex String

的 return 的数据
ValueListenableBuilder<String>(
valueListenable: _weatherStatsNotifier,
builder: (context, value, _) => NextScreen(
                                Weather: value,
                                ),
                              ),

考虑将您的方法包装在 SchedulerBinding.instance.addPostFrameCallback 中,以便在下一帧调用该方法,而不仅仅是在重建小部件时调用该方法

class _AppState extends State<App> {
  @override
  void didChangeDependencies() {
    SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
    Provider.of<WeatherStatsNotifier>(context, listen: false).refreshStats();
}
    super.didChangeDependencies();
  }


    });



当依赖项发生变化时,即 WeatherStatsNotifier,didChangeDependencies 被调用。小部件已经被认为是脏的并且正在构建(可以有多个侦听器)。

然而,您的 refreshStats 正在同步 通知监听器 这意味着应该重新构建监听器,但它们已经在构建了。这可能会导致框架不一致,所以这就是错误的原因。这也是为什么删除此 notifyListeners(); 是“解决”问题的原因。

修复它的方法是通过 addPostFrameCallbackFuture.microtask 执行异步更改。

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    Future.microtask(() {
      Provider.of<WeatherStatsNotifier>(context, listen: false).refreshStats();
    });

  }

请注意,如果您有多个依赖项,您可能应该检查 didChangeDependencies 中的实例是否已更改。