Flutter:如何为 StreamBuilder 制作 http 流

Unk*_*now 5 future http stream flutter stream-builder

你好

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

我发现我们可以用流来实现它,但每次我尝试将我的 Future In Stream 转换时,它仍然有效,但就像它是一个 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);
              });
        });
  }
}




Run Code Online (Sandbox Code Playgroud)

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

Mαπ*_*π.0 3

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

我们首先定义Future和 的区别Streams

这个SO帖子

Future就像你点外卖时他们给你的带有数字代币;您提出了请求,但结果尚未准备好,但您有一个占位符。当结果准备好时,您会收到回调(外卖柜台上方的数字板显示您的号码,或者他们大声喊出) - 您现在可以进去拿食物(结果)外卖。

一条溪流就像那条带着小寿司碗的腰带。坐在那张桌子旁,您就已经“订阅”了该流。您不知道下一艘寿司船何时到达 - 但当厨师(消息源)将其放入流(传送带)中时,订阅者就会收到它。需要注意的重要一点是,它们是异步到达的(你不知道下一艘船/消息何时到达),但它们会按顺序到达(即,如果厨师按某种顺序将三种类型的寿司放在传送带上——您会看到它们以相同的顺序出现)

现在,这是一个如何从头开始创建自己的流的示例:

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,);
            },
          )
      ),

    );
  }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

您还可以查看此 SO 帖子以获取一些参考。

在这里,我调整了上面 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());
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这里有一些教程可供更好的参考: