3

I want to display an error screen if net is not there. I am not using connectivity package because I don't want continuous check. I just want to handle exception while calling backend api and display the screen. I am unable to catch the exception.

I found this issue and this question about socket exceptions but none seem to help me.

This is how I call my backend api -

callBackendApi() async {
  try {
    http.Response response = await Future.value(/*api call here*/)
        .timeout(Duration(seconds: 90), onTimeout: () {
      print('TIME OUT HAPPENED');
    });
  } catch (exception) {
    Fluttertoast.showToast(msg: 'Check internet connection.');
    print('Error occurred' + exception.toString());
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Keerti Purswani
  • 4,878
  • 3
  • 16
  • 29

3 Answers3

11

I use dio like this:

try {

    var formData = FormData.from(Map<String, dynamic>.from(data));

    var response = await dio.post(
      uri,
      data: formData,
    );
    jsonResponse = json.decode(response.data);
  } on DioError catch (e) {

    if (DioErrorType.RECEIVE_TIMEOUT == e.type ||
        DioErrorType.CONNECT_TIMEOUT == e.type) {
      throw CommunicationTimeoutException(
          "Server is not reachable. Please verify your internet connection and try again");
    } else if (DioErrorType.RESPONSE == e.type) {
      // 4xx 5xx response
      // throw exception...
    } else if (DioErrorType.DEFAULT == e.type) {
         if (e.message.contains('SocketException')) {
           throw CommunicationTimeoutException('blabla');
         }
    } else {
          throw CommunicationException("Problem connecting to the server. Please try again.");
    }
 }
JOhn
  • 313
  • 2
  • 9
9

My solution is to import 'dart.io' in order to catch SocketException from try block:

import 'package:http/http.dart' as http;
import 'dart:io';

try{

//Handle you network call code block in here

}on SocketException catch(_){

//To handle Socket Exception in case network connection is not available during initiating your network call

}
ibarrond
  • 6,617
  • 4
  • 26
  • 45
Akradhi
  • 91
  • 1
  • 3
  • Import 'dart.io' in order to catch SocketException from try block That's all. I came in looking to resolve the same issue as yours but instead I found the resolution on my own. So, thought of sharing with the gang for future seekers that way I implemented the code to catch the SocketException. – Akradhi Jan 15 '20 at 08:09
1

Well i don't know if my answer will be solving your question but days ago i had a problem little bit likely yours but in my case was using firebase realtime database. I was asking to myself how can i protect my app from network fails like no internet connection available? Well i am not using connectivity package too so i solve this problem with an approach that you already has been try using a timeout for network operations. I will share two snipets with differents approaches that i had implemented to handle this kind of problem adding some comments trying explain the differences between them.

Approach 1 - Setting timeout outside from network request method

Well the snipet below is a simple firebase database request where _viewsRef is a DatabaseReference and the once method do the request and returns me a Future with or without data.

// get users visualization from realtime database and returns a future 
static Future<DataSnapshot> getUserVisualizations({@required String uid}) async {
    return _viewsRef.child(uid).limitToLast(50).once();
  }

In my BLoC component class i am calling the method below and setting a timeout to the future that is returned.

myBlocComponentMethod(){
    //.. some work and finally the call
    FirebaseUserViewsHelper.getUserVisualizations(uid: _currentUid)
        .then(
            (dataSnapshot){
              if (dataSnapshot.value == null) {
                  // do some things to handle no data
              }

              else {
                  /// handle your data here
                });
              }
            } // setting timeout here is an important point 
        ).timeout( Duration(seconds: Constants.NETWORK_TIMEOUT_SECONDS),
            onTimeout: (){
                  // method to handle a timeout exception and tell to view layer that
                 // network operation fails
                 // if we do not implement onTimeout callback the framework will throw a  TimeoutException
             } );
  }

Well what is the point here? In this case if the timeout expires and future is not completed yet onTimeout callback is called and there i can tell to the view layer that network operation fails and show to the user some widget about it. But even with timeout expired the request to firebase database stays happening again and again, it's like the async event of request the database stays on dart event queue. I think this behavior is bad for performance aspects but if you're building your UI using a StreamBuilder with a little logic and code your requested data will be available right when you internet connection is back and with BLoC pattern the UI can respond easily to this event and we don't need provide a refresh button by example to user make the request again. I don't know if this is the right approach to implement this behavior but it works.

Approach 2 - Setting timeout inside from network request method

Below another firebase database request method

static Future<DataSnapshot> readUserNode( {@required String uid} ) async
     => USERS_REFERENCE.child(uid).once()
          .timeout( Duration(seconds: Constants.NETWORK_TIMEOUT_SECONDS ) );
          //note: Without timeout callback this line will throw a TimeoutException if the time expires

The usage in another BLoc component:

  myBlocComponentMethod2(){
      for( String uid in  iterable ){
        FirebaseUserHelper.readUserNode(uid: uid)
            .then( (userSnapshot){

          if (userSnapshot.value == null){
            // do your stuffs
          } 

           else {
             // more stuffs to do
           }

        }).catchError( (error){
             // when timeout expired we will catch the TimeoutException HERE and handling telling
             // the UI what we need
        } );

      }
    }

The big difference here that i get was in the behavior. In this second case since i put the timeout inside the request method when the timeout expires the request event do not run anymore, it's like that request event is removed from dart event queue. This can be good from performance perspective but now we need provide a refresh button in UI for user do the data again to get data from internet again.

I don't know if this workaround will solve your problem because you tell about SocketException what is not the case that i has described and i don't know what api you are using to make your requests. Anyway i hope that the concepts described in this post helps you implement a solution in your problem.

Marcos Boaventura
  • 4,641
  • 1
  • 20
  • 27
  • Thank you for your response but as you said, my problem is not about timeout. It is about handling the socket exception. Neither do I want to know that internet connection isn't there after timeout nor do I want the request to go again when internet comes. I just need a normal exception where I come to know internet connection isn't available. – Keerti Purswani Feb 20 '19 at 12:14