flutter 在FutureBuilder中设置提供程序值

1tu0hz3e  于 2022-12-14  发布在  Flutter
关注(0)|答案(4)|浏览(193)

我有一个小部件,它向一个API发出请求,API返回一个Map。我想做的是,每次加载小部件时,不要发出相同的请求,并将列表保存到appState.myList。但是,当我在FutureBuilder中执行appState.myList = snapshot.data;时,我得到以下错误:

flutter: ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
flutter: The following assertion was thrown while dispatching notifications for MySchedule:
flutter: setState() or markNeedsBuild() called during build.
flutter: This ChangeNotifierProvider<MySchedule> widget cannot be marked as needing to build because the
flutter: framework is already in the process of building widgets. A widget can be marked as needing to be
flutter: built during the build phase only if one of its ancestors is currently building. ...

sun.dart档案:

class Sun extends StatelessWidget {
  Widget build(BuildContext context) {
    final appState = Provider.of<MySchedule>(context);
    var db = PostDB();

    Widget listBuild(appState) {
      final list = appState.myList;
      return ListView.builder(
        itemCount: list.length,
        itemBuilder: (context, index) {
          return ListTile(title: Text(list[index].title));
        },
      );
    }

    Widget futureBuild(appState) {
      return FutureBuilder(
        future: db.getPosts(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.hasData) {
            // appState.myList = snapshot.data;
            return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (context, index) {
                return ListTile(title: Text(snapshot.data[index].title));
              },
            );
          } else if (snapshot.hasError) {
            return Text("${snapshot.error}");
          }
          return Center(
            child: CircularProgressIndicator(),
          );
        },
      );
    }

    return Scaffold(
        body: appState.myList != null
            ? listBuild(appState)
            : futureBuild(appState));
  }
}

postService.dart档案:

class PostDB {
  var isLoading = false;

  Future<List<Postmodel>> getPosts() async {
    isLoading = true;
    final response =
        await http.get("https://jsonplaceholder.typicode.com/posts");

    if (response.statusCode == 200) {
      isLoading = false;
      return (json.decode(response.body) as List)
          .map((data) => Postmodel.fromJson(data))
          .toList();
    } else {
      throw Exception('Failed to load posts');
    }
  }
}

我知道myList调用了notifyListeners(),这就是导致错误的原因。希望我没有弄错。如果是这样,我如何设置appState.myList并在应用程序中使用而不出现上述错误?

import 'package:flutter/foundation.dart';
import 'package:myflutter/models/post-model.dart';

class MySchedule with ChangeNotifier {
  List<Postmodel> _myList;

  List<Postmodel> get myList => _myList;

  set myList(List<Postmodel> newValue) {
    _myList = newValue;
    notifyListeners();
  }
}
6qqygrtg

6qqygrtg1#

出现该异常的原因是,您正在从小部件的子代同步修改小部件。
这是不好的,因为它可能会导致不一致的部件树。一些部件可能是使用变异前的值构建的部件,而其他部件可能使用变异后的值。
解决方案是消除不一致性。使用ChangeNotifierProvider,通常有两种情况:

  • ChangeNotifier上执行的变异总是在与创建ChangeNotifierbuild 相同的 build 中完成。

在这种情况下,您可以直接从ChangeNotifier的构造函数进行调用:

class MyNotifier with ChangeNotifier {
  MyNotifier() {
    // TODO: start some request
  }
}
  • 所执行的更改可以“延迟”发生(通常在更改页面之后)。

在这种情况下,你应该把你的突变 Package 在一个addPostFrameCallbackFuture.microtask中:

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  MyNotifier notifier;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    final notifier = Provider.of<MyNotifier>(context);

    if (this.notifier != notifier) {
      this.notifier = notifier;
      Future.microtask(() => notifier.doSomeHttpCall());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}
3xiyfsfu

3xiyfsfu2#

我在使用提供程序时遇到过类似的问题。我的解决方案是在获取数据时添加WidgetsBinding.instance.addPostFrameCallback()

ocebsuys

ocebsuys3#

简单地从代码中删除notifyListeners();。我遇到了这个错误,这就是我解决这个问题所做的。

w46czmvw

w46czmvw4#

还有另一种方法可以解决这个问题,那就是在Future上使用StreamSubscription。这将需要更多的样板代码,但它有助于确保其他逻辑可以被分离到小部件构建材料中,以防止副作用。
第一个
请查看here中的完整示例代码。

相关问题