在带有参数的命名路由中使用FutureBuilder

时间:2019-12-05 22:35:14

标签: flutter

我有一个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参数。

1 个答案:

答案 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 {