我有一个小部件,它向返回地图的api发出请求。我不希望每次加载小部件并将列表保存到时都发出相同的请求appState.myList。但。当在中执行此操作appState.myList = snapshot.data;时FutureBuilder,出现以下错误:
appState.myList
appState.myList = snapshot.data;
FutureBuilder
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 文件:
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 文件:
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在应用中设置和使用而不会出现上述错误?
myList
notifyListeners()
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(); } }
之所以出现该异常,是因为您正在从其后代同步修改窗口小部件。
这很不好,因为它可能导致小部件树不一致。一些小部件。可能会使用突变前的值来构建窗口小部件,而其他窗口可能会使用突变后的值。
解决的办法是消除不一致之处。使用ChangeNotifierProvider,通常有两种情况:
ChangeNotifierProvider
ChangeNotifier
在这种情况下,您可以直接从您的构造函数中进行调用ChangeNotifier:
class MyNotifier with ChangeNotifier { MyNotifier() { // TODO: start some request } }
在这种情况下,您应该将突变包装在addPostFrameCallback或中Future.microtask:
addPostFrameCallback
Future.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(); } }