skip to Main Content

Let say I have stream that fetch data from api and it runs every 2 seconds:

Stream.periodic(Duration(seconds: 2), (_) {
    // API data...
});

now while this works it also sends too many requests till i get too many request error.

What I’m looking for is to have this timer run as is when user first time opens the screen then it runs let say every 35 seconds.

How can I do that?

I have this code right now that doesn’t work! (still runs every 2 seconds)

bool isFirst = true;

Stream<List<Message>> getDataStream() {
    Timer.periodic(Duration(seconds: isFirst == true ? 2 : 35), (timer) async {
      // API data...
    });
    return messageStreamController.stream;
}

Any suggestions?

2

Answers


  1. You made a little mistake in the duration , you flipped 2 with 35 .
    replace your code with this code :

    bool isFirst = true;
    
    Stream<List<Message>> getDataStream() {
        Timer.periodic(Duration(seconds: isFirst == true ? 35 : 2), (timer) async {
          // API data...
        });
        return messageStreamController.stream;
    }
    

    but I advice you to use WebSocket instead of spamming REST API , because the server will detect it as DDos attack and it will block your requests .

    Login or Signup to reply.
  2. Timer.periodic(Duration(seconds: isFirst == true ? 2 : 35), ...
    

    isFirst == true : 2 : 35 is evaluated immediately before calling the Timer.periodic constructor; it is not re-evaluated each time the Timer‘s callback fires. The period of a periodic Timer cannot be changed.

    If you want the initial event to be timed differently, that initial event is not periodic. Just handle the initial event separately. A general pattern when registering callbacks that should be triggered at least once is to register the callback and then to invoke that callback explicitly. For example:

    void onTimer(Timer timer) {
      // Do stuff...
    }
    
    var timer = Timer.periodic(const Duration(seconds: 35), onTimer);
    onTimer(timer);
    

    Or if you want to delay everything by 2 seconds, register a non-periodic Timer that sets up the periodic Timer:

    void onTimer(Timer timer) {
      // Do stuff...
    }
    
    Timer? periodicTimer;
    Timer(const Duration(seconds: 2), () {
      periodicTimer = Timer.periodic(const Duration(seconds: 35), onTimer);
      onTimer(periodicTimer!);
    });
    

    But since it seems that you really just want to generate events for a Stream, as @pskink noted, you don’t need to explicitly use Timers at all:

    Stream<List<Message>> getDataStream() async* {
      await Future.delayed(const Duration(seconds: 2));
      while (true) {
        // Do stuff...
    
        yield messages;
        await Future.delayed(const Duration(seconds: 35));
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search