如何将快照数据从 futurebuilder 传递到同一页面中的另一个 futurebuilder?
Posted
技术标签:
【中文标题】如何将快照数据从 futurebuilder 传递到同一页面中的另一个 futurebuilder?【英文标题】:How can i pass snapshot data from futurebuilder to another futurebuilder in the same page? 【发布时间】:2021-04-13 18:18:54 【问题描述】: 我是 Flutter 世界和移动应用程序开发的新手,并且正在为如何在我的应用程序中传递数据而苦苦挣扎。这是我的代码,如何将快照数据从 futurebuilder 传递到同一页面上的另一个 futurebuilder?请帮忙 **小部件 _buildProgrammCard()** 从这个小部件卡中,我需要将 futurebuilder 中的位置 ID 传递给另一个 futurebuilder。Widget _buildProgrammCard()
return Container(
height: 90,
child:
Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 4,
margin: EdgeInsets.fromLTRB(14, 0, 14, 14),
child:
FutureBuilder(
future: databaseHelper2.Lastlocation(),
builder: (context,snapshot)
if (snapshot.hasError)
print(snapshot.error);
print("there is problem");
return snapshot.hasData
? Text("Location :" +snapshot.data.id)
: Center(child: CircularProgressIndicator(
),
);
),
),
);
小部件构建(BuildContext 上下文) 这是我需要将位置 ID 从另一个小部件传递给它的第二个小部件。
Widget build(BuildContext context)
return Scaffold(
backgroundColor: Colors.grey[100],
body: FutureBuilder(
future: databaseHelper2.Getweither(location_id),
builder: (context,snapshot)
if (snapshot.hasError)
print(snapshot.error);
print("there is problem !");
return snapshot.hasData
? ItemList(list: snapshot.data)
: Center(child: CircularProgressIndicator(
),
);
),
);
【问题讨论】:
【参考方案1】:Flutter 经常重建小部件,因此 FutureBuilder 不应直接调用未来函数。 (小部件每秒最多可以调用其build
函数60 次。)
相反,FutureBuilder 应该只从其他地方调用的异步函数接收未来值。
在 StatefulWidget 中,启动长时间运行操作的最常见位置是在其 initState()
方法中。
在第一个 Widget initState 期间检索到的位置数据可以传递给第二个 Widget,就像常规的构造函数参数一样。
您将在第二个小部件的 State 类中使用 widget.locationId
访问它。
import 'package:flutter/material.dart';
class FirstFuturePage extends StatefulWidget
@override
State<StatefulWidget> createState() => FirstFutureState();
class FirstFutureState extends State<FirstFuturePage>
Future<int> locationId = Future.value(-1);
@override
void initState()
// TODO: implement initState
super.initState();
someAsyncCall();
Future<void> someAsyncCall() async
// just returns the number 0 after 2 seconds & assigns it to "locationId" var
locationId = Future.delayed(Duration(seconds: 2), () => 0);
@override
Widget build(BuildContext context)
return Scaffold(
body: SafeArea(
child: Center(
child: FutureBuilder<int>(
future: locationId,
builder: (context, snapshot)
int _locationId = snapshot.data;
if (snapshot.hasData)
return SecondWidget(_locationId);
return Text('Looking up location...');
,
),
),
),
);
class SecondWidget extends StatefulWidget
final int locationId;
SecondWidget(this.locationId);
@override
_SecondWidgetState createState() => _SecondWidgetState();
class _SecondWidgetState extends State<SecondWidget>
Future<String> weatherData = Future.value('Unknown');
@override
void initState()
super.initState();
loadWeather(widget.locationId); // Use the locationId passed into widget
/// Takes locationId from First widget and looks up weather data for location
Future<void> loadWeather(int locationId) async
List<String> weatherDataStore = List<String>.from(['Rainy', 'Sunny']);
weatherData = Future.delayed(
Duration(seconds: 2), () => weatherDataStore[locationId]
);
@override
Widget build(BuildContext context)
int _locId = widget.locationId;
return FutureBuilder<String>(
future: weatherData,
builder: (context, snapshot)
if (snapshot.hasData)
return Text('Weather for location $_locId is: $snapshot.data');
return Text('Loading Weather...');
,
);
状态管理解决方案
当您厌倦了像上面示例中那样传递值时,您可以使用状态管理包或创建适合您需要的自己的包。
以下是 Jeff Delaney 关于各种选项的精彩概述: https://fireship.io/lessons/flutter-state-management-guide/
还可以查看上面未提及的 Get: https://pub.dev/packages/get
上面的一些状态管理解决方案(例如 Provider)帮助您正确使用 Flutter 原生状态功能(因为它相当复杂),而另一些则完全避免了这种情况,并提供了一个独立于 Widget 生命周期的框架(例如 Get)。
【讨论】:
感谢 Baker 的回复,但不是我的意思!我已经发布了另一个答案来向您解释更多。【参考方案2】:感谢贝克的回复,但不完全是我的意思 这是我的两个未来和我的班级
这是我的未来,从她那里返回位置我需要将位置 ID 传递给另一个未来
Future<Location> Lastlocation() async
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key) ?? 0;
String myUrl = "$serverUrl/location/getlastlocation?token=" + value;
http.Response response = await http.get(
myUrl,
headers:
'Accept': 'application/json',
//'Authorization': 'token $value'
,
);
if (response.statusCode == 200)
// If the server did return a 200 OK response,
return Location.fromJson(json.decode(response.body));
else
// then throw an exception.
throw Exception('Failed to load album');
这是我的未来,返回取决于位置 ID 的天气列表
Future<List> Getweither(String ID) async
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key) ?? 0;
String myUrl = "$serverUrl/sensors/getDeviceByid/$ID?token=" + value;
http.Response response = await http.get(myUrl,
headers:
'Accept': 'application/json',
);
print("myUrldevice :"+myUrl);
print("status :"+response.statusCode.toString());
return json.decode(response.body);
这是我的班级位置
// To parse this JSON data, do
//
// final location = locationFromJson(jsonString);
import 'dart:convert';
List<Location> locationFromJson(String str) => List<Location>.from(json.decode(str).map((x) => Location.fromJson(x)));
String locationToJson(List<Location> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Location
Location(
this.automaticIrrigation,
this.coordinates,
this.createdDate,
this.sensorIds,
this.id,
this.siteName,
this.description,
this.v,
);
bool automaticIrrigation;
List<double> coordinates;
DateTime createdDate;
List<String> sensorIds;
String id;
String siteName;
String description;
int v;
factory Location.fromJson(Map<String, dynamic> json) => Location(
automaticIrrigation: json["AutomaticIrrigation"],
coordinates: List<double>.from(json["Coordinates"].map((x) => x.toDouble())),
createdDate: DateTime.parse(json["Created_date"]),
sensorIds: List<String>.from(json["Sensor_ids"].map((x) => x)),
id: json["_id"],
siteName: json["SiteName"],
description: json["Description"],
v: json["__v"],
);
Map<String, dynamic> toJson() =>
"AutomaticIrrigation": automaticIrrigation,
"Coordinates": List<dynamic>.from(coordinates.map((x) => x)),
"Created_date": createdDate.toIso8601String(),
"Sensor_ids": List<dynamic>.from(sensorIds.map((x) => x)),
"_id": id,
"SiteName": siteName,
"Description": description,
"__v": v,
;
这是我的主页
import 'dart:convert';
import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sidebar_animation/Services/DataHelpers.dart';
import 'package:sidebar_animation/sidebar/sidebar_layout.dart';
import '../bloc.navigation_bloc/navigation_bloc.dart';
import 'package:sidebar_animation/constants.dart';
import 'package:flutter/gestures.dart';
import 'package:sidebar_animation/bloc.navigation_bloc/navigation_bloc.dart';
class HomePage extends StatelessWidget with NavigationStates
@override
Widget build(BuildContext context)
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
class MyHomePage extends StatefulWidget
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
DatabaseHelper2 databaseHelper2 = new DatabaseHelper2();
@override
void initState()
super.initState();
@override
Widget build(BuildContext context)
return Scaffold(
backgroundColor: Colors.grey[100],
body: ListView(
FutureBuilder(
future: databaseHelper2.Getweither(location_id),
builder: (context,snapshot)
if (snapshot.hasError)
print(snapshot.error);
print("there is problem !");
return snapshot.hasData
? ItemList(list: snapshot.data)
: Center(child: CircularProgressIndicator(
),
);
),
);
Widget _buildProgrammCard()
return Container(
height: 90,
child:
Card(
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 4,
margin: EdgeInsets.fromLTRB(14, 0, 14, 14),
child:
FutureBuilder(
// future: databaseHelper.getData(),
future: databaseHelper2.Lastlocation(),
builder: (context,snapshot)
if (snapshot.hasError)
print(snapshot.error);
print("mochkla lenaa *");
return snapshot.hasData
? Text("Location :" +snapshot.data.siteName)
: Center(child: CircularProgressIndicator(
),
);
),
),
);
class ItemList extends StatelessWidget
List list;
ItemList(this.list);
ScrollController _controller = new ScrollController();
@override
Widget build(BuildContext context)
return ListView.builder(
itemCount: list == null ? 0 : list.length,
scrollDirection: Axis.horizontal,
itemExtent: 190.0,
itemBuilder: (context, index)
return Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 0, 14),
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
item.storyUrl,
),
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.black26,
BlendMode.darken,
),
),
borderRadius: BorderRadius.circular(10.0),
color: Colors.grey,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"temp :",
style: TextStyle(color: Colors.white),
),
),
Padding(
padding: EdgeInsets.only(left: 24),
child:
Text(
list[i]['Weither']['Temp'],
),
),
],
),
),
);
,
),
最后我需要从第一个 future 中获取 location id,将 Location 返回到第二个 future Getweither(String ID)。
【讨论】:
嗨 Dhouib,感谢您提供的额外细节。我希望能够引导您朝着在 Flutter 中公开通用设计模式的方向发展,并让您通过更改当前架构来学习/发现直接解决问题的方法。这里有另一个建议:使 _buildProgrammCard 成为它自己的 StatefulWidget 类,这样它就可以在创建时在其 initState 方法中启动 Lastlocation 调用。 (我假设您需要 Lastlocation 数据才能获取天气。) 感谢@baker 的评论。这很有帮助。以上是关于如何将快照数据从 futurebuilder 传递到同一页面中的另一个 futurebuilder?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Mockito 的 FutureBuilder 快照数据为空 - Flutter
将异步数据(GPS 协调)从 FutureBuilder 传递给提供者/设置异步构造函数
将快照数据从一个 dart 文件传递到颤振项目中的另一个文件