Search code examples
flutterflutter-futurebuilderflutter-lints

flutter discarded_futures when using FutureBuilder


I feel like there is an issue with the linter rule discarded_future

Is there a way to use the discarded_future lint rule without having to ignore the rule each time i'm using the FutureBuilder. Is that normal that the rule is triggered when using a simple FutureBuilder and if yes, what is the correct way to do it?

FutureBuilder<void>(
            
    future: retrieveLostData(),
    builder: (
      BuildContext context,
      AsyncSnapshot<void> snapshot,
    ) {
      switch (snapshot.connectionState) {
        case ConnectionState.none:
          return buildRowIconPhoto();
        case ConnectionState.waiting:
          return buildRowIconPhoto();
        case ConnectionState.done:
          return buildRowIconPhoto();
        default:
          return buildRowIconPhoto();
      }
    },
)
 Future<void> retrieveLostData() async {
    LostDataResponse response = await _imagePicker.retrieveLostData();
    if (response.isEmpty) {
      return;
    }
    if (response.file != null && widget.onPhotoTaken != null) {
      widget.onPhotoTaken!(
        File(response.file!.path),
        false,
      );
    }
  }

Solution

  • I completely agree with you. I fail to see why this linter warning cares whether the future attribute is accepting a synchronous future or an asynchronous one.

    Nevertheless, this is how you can get around the warning:

    class _SomeClassState extends State<SomeClass> {
      Future<void> retrieveLostData() async {
        LostDataResponse response = await _imagePicker.retrieveLostData();
        if (response.isEmpty) {
          return;
        }
        if (response.file != null && widget.onPhotoTaken != null) {
          widget.onPhotoTaken!(
            File(response.file!.path),
            false,
          );
        }
      }
    
      Future<void> retrieveLostDataFuture() async {
        _lostDataFuture = retrieveLostData();
      }
    
      late final Future<void> _lostDataFuture;
    
      @override
      void initState() {
        super.initState();
        unawaited(retrieveLostDataFuture());
      }
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder<void>(
          future: _lostDataFuture,
          builder: (
            BuildContext context,
            AsyncSnapshot<void> snapshot,
          ) {
            switch (snapshot.connectionState) {
              case ConnectionState.none:
                return buildRowIconPhoto();
              case ConnectionState.waiting:
                return buildRowIconPhoto();
              case ConnectionState.done:
                return buildRowIconPhoto();
              default:
                return buildRowIconPhoto();
            }
          },
        );
      }
    }
    

    Or, if you are not using a StatefulWidget, instead of calling retrieveLostDataFuture in initState, you can do the same in the constructor:

    class SomeClass extends StatelessWidget {
      SomeClass() {
        unawaited(retrieveLostDataFuture());
      }
    }
    

    Both variants, I'd argue, are quite ugly, and your original code is probably the best version to use.

    This code is given for those of you that are very pedantic about resolving linter warnings.