Ibrahim Ali
Ibrahim Ali

Reputation: 2511

Flutter - Stop FutureBuilder operation in between process

How do I cancel FutureBuilder operation when rebuilding the widget

Lets say I have a code like this... Every time i pressed the Floating button the widget rebuilds calling myFuture which waits five seconds and then the counter increments... Now I want that during that five seconds if I pressed the Floating button the current Future (which is still is delayed) should stop its operation and the new Future will be called...So at the end I should get a counter of 2 but instead I get 3...

class MyHomePage extends StatefulWidget {

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

class _MyHomePageState extends State<MyHomePage> {
  var counter = 0;
  
  myFuture()async{
    await Future.delayed(Duration(seconds:5));
    counter++;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: FutureBuilder(
        future: myFuture(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting)
            return Center(child: CircularProgressIndicator());
          else return Text(counter.toString());
        }
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: ()=>setState(() {}),
        child: Icon(Icons.add),
      ),
    );
  }
}
 

Upvotes: 2

Views: 2636

Answers (3)

orotype
orotype

Reputation: 459

Alternatively you can use a Stream and StreamBuilder instead of Future and FutureBuilder if that fits your use case.

void main() {
  // keep a reference to your stream subscription
  StreamSubscription<List> dataSub;
  
  // convert the Future returned by getData() into a Stream
  dataSub = getData().asStream().listen((List data) {
    updateDisplay(data);
  });

  // user navigated away!
  dataSub.cancel();
}

source: https://dart.academy/how_cancel_future/

Upvotes: 0

FDuhen
FDuhen

Reputation: 4836

In order to cancel a Future, you can use the CancelableOperation from the async package.

It's implementation would look like the following :

  Future<dynamic> executeCancelable(Future<dynamic> futureMethod) async {
    operation?.cancel();
    operation = CancelableOperation.fromFuture(futureMethod, onCancel: () {
      print('Future stopped');
    });

    return operation.value;
  }

  Future<dynamic> futureMethod() async {
    return Future.delayed(const Duration(milliseconds: 3000), () {
      return counter++;
    });
  }

Which can be called with the following method :

executeCancelable(futureMethod())

Note that in this example, I'm using a Future.delayed wich can't "really" be cancelled as explained here.
This snippet would work well with an API query for example.

Upvotes: 2

Huthaifa Muayyad
Huthaifa Muayyad

Reputation: 12383

int counter = 0;

  fiveSeconds() async {
    await Future.delayed(Duration(seconds: 5));
  
  }

    twoSeconds() async {
    await Future.delayed(Duration(seconds: 2));
    
  }

   bool _futureTime = true; 

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: FutureBuilder(
        future: _futureTime ? fiveSeconds() : twoSeconds(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting)
            return Center(child: CircularProgressIndicator());
          else counter++;
     return Text(counter.toString());
        }
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){setState(() {
       _futureTime = !_futureTime;
        });
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Upvotes: 0

Related Questions