Bloc: How to send a result of request time out to BLoC?

Created on 14 Jun 2020  路  6Comments  路  Source: felangel/bloc

Hi @felangel

I already used your package, but my question is how to send the result of request time out to the BLoC? For example, I set the max of load data from the internet is 30 seconds, when the user load data from the internet is more than 30 seconds, it will call state RTO from the BLoC.

This is the example of my BLoC:

Stream<MoviesState> _mapLoadNowPlayingToState() async* {
    var result = await Connectivity().checkConnectivity();
    if (result == ConnectivityResult.none) {
      yield MoviesNoInternetConnection(AppConstant.noInternetConnection);
    } else {
      try {
        yield MoviesLoading();
        var movies = await repository.getNowPlaying(ApiConstant.apiKey, ApiConstant.language);
        if (movies.results.isEmpty) {
          yield MoviesNoData(AppConstant.noData);
        } else {
          yield MoviesHasData(movies);
        }
      } catch (e) {
        yield MoviesError(e.toString());
      }
    }
  }

As you can see, on that BLoC I only handle for state Error, Loading, Has Data, No Data, No Internet But I need 1 condition for handle state request time out. Or you have an example of that?

question

All 6 comments

Hi @rrifafauzikomara 馃憢

I would advise you against relying on the Connectivity package to decide whether you can make a network request or not. This should rather be used to display a status where accuracy is not something crucial.
Instead you could just try to make the request and handle possible errors/exceptions/timeouts etc.
If you're using a http client like dio you can make use of the DioError which exposes a DioErrorType containing CONNECT_TIMEOUT and RECEIVE_TIMEOUT. One basic approach would be to throw app specific exceptions when timeouts occur like ReceiveTimeoutException which you could then handle in your bloc.

try {
        yield MoviesLoading();
        var movies = await repository.getNowPlaying(ApiConstant.apiKey, ApiConstant.language);
        if (movies.results.isEmpty) {
          yield MoviesNoData(AppConstant.noData);
        } else {
          yield MoviesHasData(movies);
        }
      } on ReceiveTimeoutException catch (e) {
        yield MoviesError('Server timeout!');
      } catch (e) {
        yield MoviesError(e.toString());
      }

Hope this gives you a good starting point 馃憤

Hi @RollyPeres

Thanks for the answer and sharing. Yes, I used dio for http client but how to send the result of DioErrorType (in the network layer) to the BLoC (in the logic layer)? Are you have an example of that?

And also thanks for making me remembered, I can use IOException and TimeoutException, on going to remove the Connectivity 馃憤

class ReceiveTimeoutException implements Exception {}

try {
  await dio.get(...);
} on DioError catch (e) {
  if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
    throw ReceiveTimeoutException();
  }
}

You can check out dio pub page for additional guidance on how to use their package. 馃憤

I tried with this code with test case turn off the wifi and mobile data, but not working:

Stream<MoviesState> _mapLoadTopRatedToState() async* {
    try {
      yield MoviesLoading();
      var movies = await repository.getTopRated(ApiConstant.apiKey, ApiConstant.language);
      if (movies.results.isEmpty) {
        yield MoviesNoData(AppConstant.noData);
      } else {
        yield MoviesHasData(movies);
      }
    } on DioError catch (e) {
      if (e.type == DioErrorType.RECEIVE_TIMEOUT || e.type == DioErrorType.CONNECT_TIMEOUT) {
        yield MoviesNoInternetConnection(AppConstant.noInternetConnection);
      }
    } catch (e) {
      yield MoviesError(e.toString());
    }
  }

It's called MoviesError not MoviesNoInternetConnection

And also I tried too with this:

Stream<MoviesState> _mapLoadTopRatedToState() async* {
    try {
      yield MoviesLoading();
      var movies = await repository.getTopRated(ApiConstant.apiKey, ApiConstant.language);
      if (movies.results.isEmpty) {
        yield MoviesNoData(AppConstant.noData);
      } else {
        yield MoviesHasData(movies);
      }
    } on IOException catch (_) {
      yield MoviesNoInternetConnection(AppConstant.noInternetConnection);
    } on TimeoutException catch (_) {
      yield MoviesNoInternetConnection(AppConstant.noInternetConnection);
    } catch (e) {
      yield MoviesError(e.toString());
    }
  }

And it's still not working, because it's called MoviesError not MoviesNoInternetConnection

I just gave you a basic example of how a certain timeout could be handled in a basic way.

I'd strongly advise you to read through dio's documentation to better understand how the package works and how you can deal with different types of timeout/error. FYI there's also CONNECT_TIMEOUT which is returned when there's a client side timeout which you're probably bumping into since you're sending a request when there's no network available.

You could debug and inspect that error you're getting to have a better understanding of what's going on. 馃憤

@RollyPeres Okay thanks 馃憤

Was this page helpful?
0 / 5 - 0 ratings