1
votes

Comment gérer l'exception de socket lorsque net n'est pas là?

Je souhaite afficher un écran d'erreur si net n'est pas là. Je n'utilise pas le package connectivité car je ne souhaite pas de vérification continue. Je veux juste gérer l'exception lors de l'appel de l'api backend et afficher l'écran. Je suis incapable de saisir l'exception.

J'ai trouvé ce problème et cette question sur les exceptions de socket mais aucune ne semble m'aider.

C'est ainsi que j'appelle mon 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());
  }
}


0 commentaires

3 Réponses :


1
votes

Eh bien, je ne sais pas si ma réponse résoudra votre question, mais il y a quelques jours, j'ai eu un problème un peu le vôtre, mais dans mon cas, j'utilisais la base de données en temps réel de Firebase. Je me demandais comment puis-je protéger mon application contre les échecs de réseau comme aucune connexion Internet disponible? Eh bien, je n'utilise pas non plus le package de connectivité, donc je résous ce problème avec une approche que vous avez déjà essayée en utilisant un délai d'expiration pour les opérations réseau. Je partagerai deux extraits avec différentes approches que j'avais implémentées pour gérer ce genre de problème en ajoutant quelques commentaires essayant d'expliquer les différences entre eux.

Approche 1 - Définition du délai d'expiration en dehors de la méthode de requête réseau p>

Eh bien, le snipet ci-dessous est une simple requête de base de données Firebase où _viewsRef est une DatabaseReference et la méthode once fait la requête et me renvoie un Future avec ou sans données .

  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
        } );

      }
    }

Dans ma classe de composant BLoC, j'appelle la méthode ci-dessous et je fixe un délai d'attente pour le futur qui est renvoyé.

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

Eh bien, quel est le point ici? Dans ce cas, si le délai d'expiration expire et que le futur n'est pas encore terminé, le rappel onTimeout est appelé et je peux dire à la couche de vue que le fonctionnement du réseau échoue et montrer à l'utilisateur un widget à ce sujet. Mais même avec l'expiration du délai, la requête à la base de données Firebase se reproduit encore et encore, c'est comme l'événement asynchrone de la requête, la base de données reste dans la file d'attente des événements de fléchettes. Je pense que ce comportement est mauvais pour les aspects de performance, mais si vous construisez votre interface utilisateur en utilisant un StreamBuilder avec un peu de logique et de code, vos données demandées seront disponibles dès le retour de votre connexion Internet et avec le modèle BLoC, l'interface utilisateur peut répondre facilement à cela événement et nous n'avons pas besoin de fournir un bouton d'actualisation par exemple pour que l'utilisateur fasse à nouveau la demande. Je ne sais pas si c'est la bonne approche pour implémenter ce comportement, mais cela fonctionne.

Approche 2 - Définition du délai d'expiration à l'intérieur de la méthode de requête réseau

Ci-dessous une autre méthode de requête de base de données Firebase

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
             } );
  }

L'utilisation dans un autre composant BLoc:

// 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();
  }

La grande différence ici que j'obtiens était dans le comportement. Dans ce deuxième cas, puisque j'ai mis le délai d'expiration dans la méthode de demande lorsque le délai d'expiration expire, l'événement de demande ne s'exécute plus, c'est comme si l'événement de demande était supprimé de la file d'attente des événements de fléchettes. Cela peut être bon du point de vue des performances, mais nous devons maintenant fournir un bouton d'actualisation dans l'interface utilisateur pour permettre à l'utilisateur de refaire les données pour obtenir à nouveau des données d'Internet.

Je ne sais pas si cette solution de contournement résoudra votre problème car vous parlez de SocketException ce qui n'est pas le cas que j'ai décrit et je ne sais pas quelle api vous utilisez pour faire vos demandes. Quoi qu'il en soit, j'espère que les concepts décrits dans cet article vous aideront à mettre en œuvre une solution à votre problème.


1 commentaires

Merci pour votre réponse mais comme vous l'avez dit, mon problème ne concerne pas le délai d'attente. Il s'agit de gérer l'exception de socket. Je ne veux pas non plus savoir que la connexion Internet n'est plus disponible après l'expiration du délai d'expiration, ni que la demande soit renvoyée lorsque Internet arrive. J'ai juste besoin d'une exception normale où j'apprends que la connexion Internet n'est pas disponible.



5
votes

J'utilise dio comme ceci:

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.");
    }
 }


0 commentaires

4
votes

Ma solution est d'importer 'dart.io' afin d'attraper SocketException du bloc try:

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

}


1 commentaires

Importez 'dart.io' afin d'attraper SocketException du bloc try C'est tout. Je suis venu chercher à résoudre le même problème que le vôtre, mais j'ai trouvé la solution par moi-même. Donc, j'ai pensé à partager avec le gang pour les futurs chercheurs de cette façon, j'ai implémenté le code pour attraper l'exception SocketException.