我有一个ListView
,代表会话列表(收件箱)。当用户点击列表项(会话)时,我们将推到以会话ID作为参数的命名路由。
在新窗口中,我们根据传递的参数(对话ID)使用FutureBuilder
获取对话消息(http请求)。
一切正常,除了当用户单击后退按钮时,再次调用build方法,并在窗口开始关闭时发出新的http请求。
我知道不建议在构建方法中创建Future
,但是在这种情况下,也最好是获取传递的参数的最佳方法。
将来一定要早一些,例如在State.initState,State.didUpdateConfig或State.didChangeDependencies中。构造FutureBuilder时,不得在State.build或StatelessWidget.build方法调用期间创建它。如果Future是与FutureBuilder同时创建的,则每次FutureBuilder的父代重建时,异步任务都将重新启动。
这是我的简化代码:
class Messages extends StatefulWidget {
@override
_MessagesState createState() => _MessagesState();
}
class _MessagesState extends State<Messages> {
@override
Widget build(BuildContext context) {
final String conversationID = ModalRoute.of(context).settings.arguments;
print("Conv: $conversationID");
final messages = Api.getMessages(conversationID);
return Scaffold(
appBar: AppBar(
title: Text("Messages"),
),
body: FutureBuilder<dynamic>(
future: messages,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.active:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
}
return Center(child: Text("messages"));
}));
}
}
在这里,两次调用build方法:一次是在打开窗口时,一次是关闭时,发出2个http请求。
如果将来将消息移到build方法之外,则我将无法访问从Navigator传递的sessionID参数。
答案 0 :(得分:1)
您应该从_MessageState覆盖方法initState;
@override
void initState() {
super.initState();
final String conversationID = ModalRoute.of(context).settings.arguments;
final messages = Api.getMessages(conversationID);
}
此外,您应该在覆盖上方声明对象,这样,第一次进入屏幕时,它将进行调用,但在下一次调用时,将不会进行调用。另外,当您将其保存在变量中时,您无需进行其他调用,它只会加载已保存的内容
代码示例:
Future<dynamic> messages;
@override
void initState() {
super.initState();
final String conversationID = ModalRoute.of(context).settings.arguments;
final messages = Api.getMessages(conversationID);
}
其余代码将相同。
希望有帮助
这是我所做的一个项目示例:
[EDIT]类的声明:
class mainMenu extends StatefulWidget {
String firebase_uid;
TextStyle style = TextStyle(fontFamily: 'Montserrat', fontSize: 20.0);
mainMenu({Key key, @required this.firebase_uid}) : super(key: key);
Future<UserCompleteObject> user;
@override
_MyHomePageState createState() => _MyHomePageState(firebase_uid);
}
[EDIT] ...导航至课程:
Future navigateToMainMenu(context, uid) async {
Navigator.push(context,
MaterialPageRoute(builder: (context) => mainMenu(firebase_uid: uid)));
}
... 未来的future_user;
@override
void initState() {
super.initState();
//Consigue los datos iniciales de los usuarios
future_user = get_datos_user_app(key, UUID);
}
.....
child: FutureBuilder<UserCompleteObject>(
future: future_user,
builder: (context, snapshot) {
if (snapshot.hasData) {
...
Future<UserCompleteObject> get_datos_user_app(String key, String UID) async {