【问题标题】:Flutter : How to make an http stream for StreamBuilderFlutter:如何为 StreamBuilder 制作 http 流
【发布时间】:2023-03-18 00:32:01
【问题描述】:

你好

我正在尝试使用 Flutter 制作我的第一个社交应用,但遇到了困难。 我想从我的 api 获取我的消息(在两个用户之间的对话中)。 当我使用 Future 和 Future Builder 时没有问题,但我希望在发送新消息时更新消息列表!

我发现我们可以使用流实现它,但是每次我尝试在流中转换我的 Future 时,它​​仍然有效,但就像它是一个 Future(它永远不会更新新消息)。

这里是我的代码的简化部分:


class Test extends StatelessWidget {
  
  final Conv conv;
  final User otherUser;

  const Test({Key key, this.conv, this.otherUser}) : super(key: key);
  
  

  Stream<List<Message>> messageFlow(String convId) {
    return Stream.fromFuture(getMessages(convId));
  }

  Future<List<Message>> getMessages(String convId) async {
    var data = await http
        .post(MyApiUrl, headers: <String, String>{}, body: <String, String>{
      "someParam": "param",
      "id": convId,
    });
    var jsonData = json.decode(data.body);

    List<Message> messages = [];
    for (var m in jsonData) {
      Message message = Message.fromJson(m);
      messages.add(message);
    }
    return messages;
  }


  
  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
        stream: messageFlow(conv.id),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.data == null) {
            return Container(
              child: Center(
                child: Text('Loading'),
              ),
            );
          }
          return ListView.builder(
              reverse: true,
              controller: _messagesListController,
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, int index) {
                Message message = snapshot.data[index];
                var isMe = message.owner == otherUser.id ? false : true;
                return _buildMessage(message, isMe);
              });
        });
  }
}




如果你能帮助我,那就太好了!

【问题讨论】:

  • Future 转换为Stream 与您发现的仅使用Future 基本相同。您需要创建自己的Stream,它会定期执行您现有的Future。查看this 的“从头开始创建流”部分。

标签: http flutter stream future stream-builder


【解决方案1】:

这对我有用

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as HTTP;

class PeriodicRequester extends StatelessWidget {
Stream<http.Response> getRandomNumberFact() async* {
yield* Stream.periodic(Duration(seconds: 5), (_) {
  return http.get("http://numbersapi.com/random/");
}).asyncMap((event) async => await event);
}

@override
Widget build(BuildContext context) {
return StreamBuilder<http.Response>(
  stream: getRandomNumberFact(),
  builder: (context, snapshot) => snapshot.hasData
      ? Center(child: Text(snapshot.data.body))
      : CircularProgressIndicator(),
);
}
}

【讨论】:

    【解决方案2】:

    我无法复制您的示例代码,但在这里我是如何理解您的问题的。

    我们先来定义一下FutureStreams的区别:

    来自this SO post

    Future 就像带有数字的令牌,当他们给你 你点外卖;你提出了请求,但结果还没有 准备好了,但你有一个占位符。当结果准备好时,你 获得回电(外卖柜台上方的数字板显示您的 号码或他们喊出来) - 你现在可以进去拿你的食物 (结果)取出。

    溪流就像那条背着小寿司碗的腰带。通过坐 在那张桌子上,您已经“订阅”了该流。你不知道 下一艘寿司船何时到达 - 但当厨师(消息 source) 将其放在流(带)中,然后订阅者将 收到它。需要注意的重要一点是他们到达 异步(你不知道下一条船/消息什么时候来) 但它们将按顺序到达(即,如果厨师放置三种类型 腰带上的寿司,按顺序排列——你会看到它们从你身边走过 以相同的顺序)

    下面是一个例子,告诉你如何create your own stream from scratch

    import 'dart:async';
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
    
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
    
      // 1st approach
      final StreamController _streamController = StreamController();
     
      addData()async{
        for(int i = 1; i<= 10; i++) {
          await Future.delayed(Duration(seconds: 1));
    
          _streamController.sink.add(i);
        }
      }
    
      // 2nd approach
      // This approach will prevent some approach of memory leaks
      Stream<int> numberStream() async*{
        for(int i = 1; i<= 10; i++) {
          await Future.delayed(Duration(seconds: 1));
    
          yield i;
        }
      }
    
      @override
      void dispose() {
        // TODO: implement dispose
        super.dispose();
        _streamController.close();
      }
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
        addData();
      }
    
      @override
      Widget build(BuildContext context) {
    
        return Scaffold(
          appBar: AppBar(
    
            title: Text("Stream"),
          ),
          body: Center(
              child: StreamBuilder(
                stream: numberStream().map((number) => "number $number"),
                builder: (context, snapshot){
                  if(snapshot.hasError)
                    return Text("hey there is some error");
                  else if (snapshot.connectionState == ConnectionState.waiting)
                    return CircularProgressIndicator();
                  return Text("${snapshot.data}", style: Theme.of(context).textTheme.display1,);
                },
              )
          ),
    
        );
      }
    }
    

    您也可以查看this SO post 以获取一些参考资料。

    在这里,我调整了上面 SO 帖子中的示例,以创建一个迷你简单的聊天服务器来显示消息如何更新。

    import 'dart:async';
    import 'package:flutter/material.dart';
    
    class Server {
      StreamController<String> _controller = new StreamController.broadcast();
      void simulateMessage(String message) {
        _controller.add(message);
      }
    
      Stream get messages => _controller.stream;
    }
    
    final server = new Server();
    
    class HomeScreen extends StatefulWidget {
      @override
      _HomeScreenState createState() => new _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> {
      List<String> _messages = <String>[];
      StreamSubscription<String> _subscription;
    
      @override
      void initState() {
        _subscription = server.messages.listen((message) async => setState(() {
              _messages.add(message);
            }));
        super.initState();
      }
    
      @override
      void dispose() {
        _subscription.cancel();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        TextStyle textStyle = Theme.of(context).textTheme.display2;
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Sample App'),
          ),
          body: new ListView(
            children: _messages.map((String message) {
              return new Card(
                child: new Container(
                  height: 100.0,
                  child: new Center(
                    child: new Text(message, style: textStyle),
                  ),
                ),
              );
            }).toList(),
          ),
          floatingActionButton: Column(
            mainAxisAlignment: MainAxisAlignment.end,
            crossAxisAlignment: CrossAxisAlignment.end,
            children: [
              new FloatingActionButton(
                child: new Icon(Icons.account_circle_outlined),
                onPressed: () {
                  // simulate a message arriving
                  server.simulateMessage('Hello World');
                },
              ),
              SizedBox(
                height: 20.0,
              ),
              new FloatingActionButton(
                child: new Icon(Icons.account_circle_rounded),
                onPressed: () {
                  // simulate a message arriving
                  server.simulateMessage('Hi Flutter');
                },
              ),
            ],
          ),
        );
      }
    }
    
    class SampleApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          home: new HomeScreen(),
        );
      }
    }
    
    void main() {
      runApp(new SampleApp());
    }
    

    这里有一些教程可以更好地参考:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-21
      • 2020-06-25
      • 2019-10-26
      • 1970-01-01
      • 2021-07-11
      • 2018-12-28
      • 2021-09-30
      • 2021-04-09
      相关资源
      最近更新 更多