Flutter-StreamBuilder-刷新

时间:2020-03-02 10:34:29

标签: flutter

我的UserListDart窗口小部件版本中有一个StreamBuilder:

StreamBuilder(
  stream: stream.asStream(),
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    if(snapshot.hasData) {
      return Expanded(
        child: ListView.builder(
          itemCount: snapshot.data.length,
          itemBuilder: (BuildContext context, int index) {
            return ListTile(
              title: Text(
                snapshot.data[index].firstname + " " +
                snapshot.data[index].lastname
              ),
              onTap: () {
                Navigator.of(context).push(DetailScreenDart(snapshot.data[index]));
              },
            ); 
          }
        )
      );
    }
  }
    ...
)

流在initState中定义:

Future<List> stream; 

@override
void initState() {
  super.initState();
  stream = fetchPost();
}

fetchPost()是一个api调用:

Future<List<User>> fetchPost() async {
  final response = await http.get('url');
  final jsonResponse = json.decode(response.body);

  List<User> users = [];

  for(var u in jsonResponse){
    User user = User(
      firstname: u["firstname"],
      lastname: u["lastname"],
    );
    users.add(user);
  }
  return users;
}

我导航到另一个页面进行更改,例如更改名字(api得到更新),然后导航回UserList:

Navigator.pushReplacement(
  context,
  new MaterialPageRoute(builder: (context) => new UserListDart())
).then((onValue) {
  fetchPost();
});

但是StreamBuilder不会更新,我也不知道为什么。

注意:

我认为当我向后浏览时,StreamBuilder并没有意识到已经发生了更改。仅当我重新打开页面时,才会应用更改。

1 个答案:

答案 0 :(得分:2)

您应该使用setState并使用stream调用的结果更新fetchList()变量:

Navigator.pushReplacement(
  context,
  new MaterialPageRoute(builder: (context) => new UserListDart())
).then((onValue) {
  setState((){
    stream = fetchPost();
  });
});

这是您要实现的目标的一个可行示例:

class StreamBuilderIssue extends StatefulWidget {
  @override
  _StreamBuilderIssueState createState() => _StreamBuilderIssueState();
}

class _StreamBuilderIssueState extends State<StreamBuilderIssue> {
  Future<List<String>> futureList;
  List<String> itemList = [
    'item 1',
    'item 1',
    'item 1',
    'item 1',
    'item 1',
  ];

  @override
  void initState() {
    futureList = fetchList();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          Expanded(
            child: Center(
              child: StreamBuilder(
                stream: futureList.asStream(),
                builder: (context, snapshot){
                  if(snapshot.hasData){
                    return ListView.builder(
                      itemCount: snapshot.data.length,
                      itemBuilder: (context, index){
                        return Text(snapshot.data[index]);
                      },
                    );
                  }else{
                    return CircularProgressIndicator();
                  }
                },
              ),
            ),
          ),
          RaisedButton(
            onPressed: goToAnotherView,
            child: Text('Next View'),
          ),
          RaisedButton(
            onPressed: addItem,
            child: Text('AddItem'),
          )
        ],
      ),
    );
  }

  Future<List<String>> fetchList(){
    return Future.delayed(Duration(seconds: 2), (){
      return itemList;
    });
  }

  void goToAnotherView(){
    Navigator.push(context, MaterialPageRoute(
      builder: (context){
        return StreamBuilderIssueNewView(addItem);
      })
    ).then((res){
      setState(() {
        futureList = fetchList();
      });
    });
  }

  void addItem(){
    itemList.add('anotherItem');
  }
}

class StreamBuilderIssueNewView extends StatelessWidget {
  final Function buttonAction;

  StreamBuilderIssueNewView(this.buttonAction);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          children: <Widget>[
            Text('New view'),
            RaisedButton(
              onPressed: buttonAction,
              child: Text('AddItem'),
            )
          ],
        ),
      ),
    );
  }
}

顺便说一句,您也可以只使用FutureBuilder,因为您这里没有使用真正的Stream,只是使用api提取,无论如何您都必须用setState更新。