3

In my Flutter app StreamSubscription is not pausing or cancelling. When I call cancel() if it started before, it will stop. If I call cancel() after starting, it will not stop. I am using Firestore snapshot listener. Below is my code. I have tried different methods but it's still not working. The problem is that the Firestore listener is not stopping after loading data.

    StreamSubscription<QuerySnapshot> streamSubscription;

    @override
    void initState() {
    super.initState();
    
        print("Creating a streamSubscription...");
        streamSubscription =Firestore.collection("name").document("d1").collection("d1")
            .snapshots().listen((data){
                //It will display items
            }, onDone: () { // Not excecuting
                print("Task Done");
            }, onError: (error) {
                print("Some Error");
        });
         streamSubscription.cancel(); //It will work but cancel stream before loading
    }

    @override
    void dispose() {
     streamSubscription.cancel(); //Not working
    super.dispose();
    }
Sludge
  • 6,072
  • 5
  • 31
  • 43
Joe
  • 959
  • 2
  • 11
  • 27
  • `stream.close()` should be `stream.cancel()` and a `StreamSubscription` should rather be called `streamSubscription` or `subscription` instead of `stream` because that's quite confusing because a `Stream` is something else entirely. – Günter Zöchbauer Feb 27 '19 at 07:18
  • There is no `close()` in https://api.dartlang.org/stable/2.2.0/dart-async/StreamSubscription-class.html so it is not surprising that it does not work. If you get an error message you should post that error message with your question. – Günter Zöchbauer Feb 27 '19 at 07:18
  • I have edited my question. I am using 'cancel()' not close. Sorry for mistake happen. – Joe Feb 27 '19 at 07:31
  • @GünterZöchbauer did u know why it is not stoping? – Joe Feb 27 '19 at 07:51
  • Hard to tell. Perhaps because the events are emitted sync and therefore emitted before `cancel()` is called. Your question is not clear enough about what's actually happening and what the expected behavior is instead. If you could improve that it would rise probability that you'll get a helpful answer. – Günter Zöchbauer Feb 27 '19 at 07:53
  • @GünterZöchbauer when I am going to another page that listener is not stoping. It is executing new page and interrupting another listeners. I have add cancel in dispose() it is not cancelling and executing new page. – Joe Feb 27 '19 at 08:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/189118/discussion-between-joe-and-gunter-zochbauer). – Joe Feb 27 '19 at 09:56

3 Answers3

4

When you push a new page, the previous page is still rendered and therefore dispose() is not called.

Also sometimes it can happen that the widget is not rendered anymore but dispose was not yet called, which can lead to weird error messages. So adding such a check is probably a good idea as well if you use dispose.

Change

//It will display items

to

if(myIsCurrentRoute && mounted) {
  //It will display items
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
2

You are not assigning the subscription into the right variable.

StreamSubscription<QuerySnapshot> subscription;

@override
void initState() {
super.initState();

    print("Creating a streamSubscription...");
    subscription=Firestore.collection("name").document("d1").collection("d1")
        .snapshots().listen((data){
            //It will display items
        }, onDone: () { // Not excecuting
            print("Task Done");
        }, onError: (error) {
            print("Some Error");
    });


     subscription.cancel(); //It will work but cancel stream before loading



}

@override
void dispose() {
 subscription.cancel(); //Not working
super.dispose();
}
dshukertjr
  • 15,244
  • 11
  • 57
  • 94
  • 1
    That is the mistake in my question. I change my question. I assigned in. correct the subscription in right variable. Please again check question and check your answer. – Joe Feb 27 '19 at 08:43
  • @Joe Have you tried if the dispose function is being called at all? Try printing something inside the dispose function and see if it is being called. – dshukertjr Feb 27 '19 at 08:48
  • 1
    I have tried in `dispose()` my dispose() is working but not cancelling the listen. I also called before calling new screen. `Navigator.push(context,MaterialPageRoute(builder: (context) => SecondScreen()));` – Joe Feb 27 '19 at 09:29
  • Can someone please tell me why onDone is not executing here ? – Piyush Jain Aug 11 '20 at 04:59
1

I was experiencing the same problem and it turns out that the stream seems to keep listening for events for a while before canceling, but if you debug you will see that after dispose is called it will stop listening at some point. Therefore, Gunter's solution works fine, since you can prevent your callback function from being called if mount is false, which means your page is no longer there.

dcg
  • 691
  • 7
  • 13