Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cancel or psuedo cancel an http request? - Flutter

Tags:

flutter

dart

I have a search bar, when characters are entered it sends a request to a BLoC, which then requests data from a Future.

Here is the BLoC

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:stockrails/models/semantics/error-type-model.dart';
import 'package:stockrails/models/user-interface/search-query-model.dart';
import 'package:stockrails/services/apis/stock-data.dart';
import 'package:stockrails/shared/constants/messages.dart';

part 'search_event.dart';
part 'search_state.dart';

class SearchBloc extends Bloc<SearchEvent, SearchState> {
  SearchBloc() : super(SearchInitial());

  // Connection to api service
  StockData _data = StockData();

  @override
  Stream<SearchState> mapEventToState(
    SearchEvent event,
  ) async* {
    // : Initial search state - no text has been entered, no loading
    if (event is SearchIntializeEvent) {
      yield SearchInitial();
    }
    // : Querying search state - text is being entered, loading next
    if (event is SearchQueryingEvent) {
      // Yields call
      yield* _mapAPICallToEvent(event.query);
    }
  }

  // + ----------- Functions -------------

  Stream<SearchState> _mapAPICallToEvent(String query) async* {
    // : Yield loading screen based on prior state
    if (state is SearchErrorState)
      yield SearchErrorLoadingState();
    else
      yield SearchLoadingState(query: query);

    // : Attempts to call method
    List<SearchQueryModel> _result;

    try {
      _result = await _data.searchQuery(query);
    } on TimeoutException {
      _result = null;
    } catch (err) {
      _result = [];
    }

    // : If it can't then it defaults to using the unknownErrorMessage
    if (_result == null)
      yield SearchErrorState(errorMessage: Messages.unknownErrorMessage, errorType: ErrorType.errorTypes[0]);

    // : Else if there's no content in the response
    else if (_result.length == 0)
      yield SearchErrorState(errorMessage: query, errorType: ErrorType.errorTypes[1]);

    // : If there's no errors return loaded!
    else {
      yield SearchLoadedState(searchQueryModelList: _result, query: query);
    }
  }
}

And here is the Future that grabs data

  // Grabs data from endpoint and returns or errors
  // If it times out it will throw a TimeoutException
  Future _dataFetch(String url, String query, String token) async {
    try {
      // Build out auth header
      final authHeader = 'Bearer $token';

      final response = await http
          .get(url, headers: <String, String>{
            'query': query,
            'authorization': authHeader,
          })
          .timeout(Duration(seconds: 10))
          .catchError((error) {
            throw error;
          });

      // Makes sure response is okay
      if (response.statusCode == 200) {
        return json.decode(response.body);
      }

      // If status code is unknown, prints an error
      else {
        throw Exception(Messages.unknownErrorMessage);
      }
    } on TimeoutException catch (error) {
      throw error;
    } on SocketException catch (error) {
      throw error;
    } catch (error) {
      throw error;
    }
  }



I've been banging my head against a wall trying to figure out a solution to make the BLoC await for the Future but also to allow SearchInitializeEvent to cancel any requests being made.

Because what's happening is on a bad network, the request is trying to go through no matter what and won't stop until it gets a response.

I know you can't cancel Futures, I tried both CancelableOperation and 'CancelableCompletion` or whatever it's called.

I'm guessing I have to setup my Future as a Stream instead so I can close it. I'm open to any suggestions. Thank you in advance!

like image 505
tyirvine Avatar asked Nov 07 '22 06:11

tyirvine


1 Answers

There's a limitation in dart for breaking Streams. It's something that can't be done outside the "loop". This is issue was discussed in detail here:

https://github.com/dart-lang/sdk/issues/42717

https://github.com/felangel/bloc/issues/1472

You may want to look into this from a different perspective, like overriding the changes made by the recent request. Or if the request results are something that's displayed on screen, then consider not displaying the results instead.

like image 141
Omatt Avatar answered Nov 15 '22 08:11

Omatt