Nikhil R
Nikhil R

Reputation: 115

How to store stream data and display new one along with old in a flutter list view?

I'm trying to display a comment stream from Reddit API. I"m using Streambuilder to stream contents as it arrives and displays it as list view thing is I can only view present stream content and this will disappear as new stream contents appear replacing the old ones. If I don't mention item count inside listview.builder prints contents infinitely still new stream appears.

is there a way to display contents along with previous contents in a scrollable fashion and automatically scroll down as a new stream message appears??

Upvotes: 0

Views: 1706

Answers (1)

downgrade
downgrade

Reputation: 88

Assuming that the comment stream returns individual (and preferably unique) comments one at a time rather than as a list, what you need to do is store the incoming comments in a state object such as a list. When a new comment comes through the stream, you add it to the list and then trigger a widget rebuild.

What you are doing right now is replacing state with each new stream element rather than accumulating them. Using the code you provided, I have edited it to behave as an accumulator instead. Notice the List<Comment> comments = <Comment>[] object added to state. I have also removed the StreamBuilder since that isn't helpful for this use case.

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:draw/draw.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: RedditFlutter(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class RedditFlutter extends StatefulWidget {
  RedditFlutter({Key key}) : super(key: key);

  @override
  _RedditFlutterState createState() => _RedditFlutterState();
}

class _RedditFlutterState extends State<RedditFlutter> {
  var comments;
  ScrollController _scrollController =
      new ScrollController(initialScrollOffset: 50.0);
  List<Comment> comments = <Comment>[];
  StreamSubscription<Comment>? sub;

  var msg = '';
  Future<void> redditmain() async {
    // Create the `Reddit` instance and authenticated
    Reddit reddit = await Reddit.createScriptInstance(
      clientId: 'clientid',
      clientSecret: 'clientsecret',
      userAgent: 'useragent',
      username: 'username',
      password: 'password', // Fake
    );

    // Listen to comment stream and accumulate new comments into comments list
    sub = reddit.subreddit('cricket').stream.comments().listen((comment) {
      if (comment != null) {
        // Rebuild from state when a new comment is accumulated
        setState(() {
          comments.add(comment);
        })
      }
    });
  }

  @override
  void initState() {
    // TODO: implement initState
    redditmain();

    super.initState();
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Reddit"),
        centerTitle: true,
      ),
      body: Center(
        child: Container(
                child: ListView.builder(
                  controller: _scrollController,
                  itemCount: comments.length,
                  itemBuilder: (context, index) {
                    final Comment comment = comments[index];
                    return Card(
                      child: ListTile(
                        leading: Image.asset('assets/criclogo.png'),
                        title: Text(comment.body),
                        trailing: Icon(Icons.more_vert),
                      ),
                    );
                  },
                ),
              );
      ),
    );
  }

  @override
  void dispose() {
    sub?.cancel();
    super.dispose();
  }
}

Note that I have not tested this code so there may be (trivial) bugs. Still, conceptually, it should be fine.

Upvotes: 2

Related Questions