问题描述
在使用FutureBuilder来显示加载指示时,如何仅获取一次数据?
问题在于,即使我在initState()中设置了将来,每次用户打开屏幕时,它都会重新获取数据。
我只想在用户第一次打开屏幕时获取数据,然后我将使用保存的获取数据。
我应该只使用带有加载变量的有状态小部件并将其设置在setState()中吗?
我正在使用提供程序包
Future<void> fetchData() async { try { final response = await http.get(url,headers: {'Authorization': 'Bearer $_token'});......
@H_502_13@和我的屏幕小部件:
class _MyScreenState extends State<MyScreen> { Future<void> fetchData; @override void initState() { fetchData = Provider.of<Data>(context,listen: false).fetchData(); super.initState(); } @override Widget build(BuildContext context) { return FutureBuilder( future: fetchData,builder: (ctx,snapshot) => snapshot.connectionState == ConnectionState.done ? Consumer<Data>( builder: (context,data,child) => Text(data.fetchedData)): Center( child: CircularProgressIndicator(),),); } }
@H_502_13@解决方法
一种简单的方法是引入StatefulWidget,将Future存放在变量中。现在,每次重建都将引用相同的Future实例:
class MyWidget extends StatefulWidget { @override _MyWidgetState createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { Future<String> _future; @override void initState() { _future = callAsyncFetch(); super.initState(); } @override Widget build(context) { return FutureBuilder<String>( future: _future,builder: (context,snapshot) { // ... } ); } }
或者您可以简单地使用FutureProvider代替上面的StatefulWidget:
,class MyWidget extends StatelessWidget { // Future<String> callAsyncFetch() => Future.delayed(Duration(seconds: 2),() => "hi"); @override Widget build(BuildContext context) { // print('building widget'); return FutureProvider<String>( create: (_) { // print('calling future'); return callAsyncFetch(); },child: Consumer<String>( builder: (_,value,__) => Text(value ?? 'Loading...'),),); } }
如果即使小部件重建,也只希望获取一次数据,则必须为此创建一个模型。这是您的制作方法:
class MyModel{ String value; Future<String> fetchData() async { if(value==null){ try { final response = await http.get(url,headers: {'Authorization': 'Bearer $_token'});...... value=(YourReturnedString) } } return value; } }
不要忘记将MyModel设置为提供程序。在您的FutureBuilder中:
,@override Widget build(context) { final myModel=Provider.of<MyModel>(context) return FutureBuilder<String>( future: myModel.fetchData(),snapshot) { // ... } ); }
您可以实现 provider 并在其子级之间传递数据。 请参阅此example for fetching the data once and using it throughout its child.