How to delete data from StreamBuilder after reading?
Asked Answered
E

4

6

I want to delete data from my stream after I read it.
Basically I want the same system than channel in Go.

So, if I add 5, 3 and 2, my stream contains 5, 3 and 2.
When I start reading, I get 5, and my stream now contains 3 and 2 etc...

Is it possible?

EDIT: Here my problem with some code.
I use a StreamBuilder to receive data. When I change the state, it trigger again my function like if I'd just receive data.

child: StreamBuilder<Tag>(
  stream: widget.tagStream,
  initialData: Tag(),
  builder: (BuildContext context, AsyncSnapshot<Tag> snapshot) {
    /// This should be trigger only when I receive data
    if (mapController.ready && snapshot.hasData) {
      tag = snapshot.data;
      mapController.move(
        LatLng(tag.position.latitude, tag.position.longitude),
        mapController.zoom);
    }
    return RubberBottomSheet(...);
),

Here some context:
I have a map with icons representing objects. When I click on an icon or if I search the item related on my search bar, a RubberBottomSheet appears to show informations about the object. To do that, I use a StreamBuilder, so I just need to put the object clicked or searched in it to make my rubber appears and fill in. I also need to centrer on my icon to let the user know where is the object. My problem is that when I open or close my keyboard or when I use a setState (for changing the appearance of my search bar for example), it automatically trigger the StreamBuilder like if it receive new data.

Sorry, I should have started here...

Eskimoaleut answered 22/7, 2019 at 10:12 Comment(9)
So you want to have an iterable?Hera
That's the default behavior actuallyCrystallization
Indeed, thanks. So my probleme should come from the StreamBuilder and/or the AsyncSnapshot, right?Eskimoaleut
Didn't get you.Hooper
I'm using a StreamBuilder to receive datas from my stream. And when I change the state, it trigger again the StreamBuilder like if it receive another data.Eskimoaleut
Ok so what is the problem you are facing? Please add some relevant code which isn't working as expected.Hooper
I don't understand your use case here. setState will rebuild. I believe you are trying to do some map related thing. Maybe if you could add what you are trying to do there we could suggest an alternative way to do it.Hooper
Is the RubberBottomSheet consuming the stream data?Hooper
@Hooper what do you mean? The data stream should be consumed here tag = snapshot.data;Eskimoaleut
V
5

I've had similar behavior with a StreamBuilder and I couldn't find a solution for days. What I did instead is use a ListView builder that takes data from an InheritedWidget instead.

So basically instead of having to put data into the stream sink, I simply wrap my data setter in the InheritedWidget in a setState() and the ListView rebuilds every time I change the data.

N.B: My StreamBuilder also involved a map, I've always thought it was the one interfering with it but I never got to solve the problem. As in your case, every time I change the state, the stream rebuilds with the same data it had before.

Videlicet answered 11/8, 2019 at 9:51 Comment(0)
E
5

The answer of Amine seems to be the best, but I'd like to share my solution too, maybe it'll help some persons.

After I've executed my code, I pass an empty object to my Stream. I just have to verify that my object is not empty before executing my code and everything works like a charm.

builder: (BuildContext context, AsyncSnapshot<Tag> snapshot) {
  if (mapController.ready &&
      snapshot.hasData &&
      snapshot.data.mobile.nid != 0) {
    tag = snapshot.data;
    ... /// My code
    widget.tagStream.sink.add(Tag());
  }
Eskimoaleut answered 12/8, 2019 at 10:55 Comment(1)
I was trying to understand the issue for like two days when reached this post, you just saved my day, haven't you found a "more clear" solution maybe? What I am thinking right now, is to make some kind of a self cleaning stream, so I wouldn't need to expose streams sink to the view, it feels like it is breaking the encapsulation and single responsibility principles.Hunker
C
1

Have similar problem in my app.
Workaroung I found is quite simple - global variable, which by default will do nothing ("false" in this example). But in method which need to call setState() change this variable value to block next snapshot.data when rebuilding widget (in this example value "true" will block).
Remember to change variable to default value or you won't get new stream updates.

    // global variable - doing nothing by default
    bool _clear = false;
    (...)
    /// Add additional condition
    if (mapController.ready && snapshot.hasData && !_clear) {
      tag = snapshot.data;
      mapController.move(
        LatLng(tag.position.latitude, tag.position.longitude),
        mapController.zoom);
    }
    /// change variable to default value
    _clear = false;
    return RubberBottomSheet(...);
    ),
(...)
// some method calling setState
void _clearMethod() {
    _clear = true;
    setState(() {});
}
Capo answered 22/7, 2021 at 19:22 Comment(0)
S
0

I had a similar problem, when you check the condition stream.hasData it will trigger even if you already "consumed" that information, so what I did was identify the data using the data's hashCode.

Basically, I have an int variable storing the previous data hashCode, when checking if the stream has data, I'll also check if that data's hashCode is different than the previous one, in other words if it is a new data. Like this:

// variable declared at the page state, before the build() method
int? lastHashStream;

// now inside the StreamBuilder builder method, before returning any widget
if (snapshot.hasData) {
  if (lastHashStream == null || snapshot.data.hashCode != lastHashStream) {
    lastHashStream ??= snapshot.data.hashCode;
    // your commands
  } // else is when there has been some message and it is the same as the previous
}

It doesn't remove the data from the stream, but you can check if it's new data which was enough for me, I hope it helps.

Scrapbook answered 27/6, 2023 at 14:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.