2014-02-18 6 views
64

Ich verwende Volley für meine Android-App, um Daten von meinem Server zu holen. Es funktioniert gut, außer wenn der Fehler von meinem Server behandelt wird. Mein Server sendet diese Antwort, wenn es ein Fehler ist:Android: Wie behandeln Nachricht Fehler vom Server mit Volley?

{ 
    "status": 400, 
    "message": "Errors (2): A name is required- Julien is already used. Not creating." 
} 

Mein Ziel ist es, die Nachricht zu bekommen und es dann in einem Toast anzuzeigen. Ich habe ein Beispiel dafür genommen, wie es geht, aber es funktioniert nicht.

Es ist mein Fehler Zuhörer:

public void onErrorResponse(VolleyError error) { 
      int statusCode = error.networkResponse.statusCode; 
      NetworkResponse response = error.networkResponse; 

      Log.d("testerror",""+statusCode+" "+response.data); 
      // Handle your error types accordingly.For Timeout & No connection error, you can show 'retry' button. 
      // For AuthFailure, you can re login with user credentials. 
      // For ClientError, 400 & 401, Errors happening on client side when sending api request. 
      // In this case you can check how client is forming the api and debug accordingly. 
      // For ServerError 5xx, you can do retry or handle accordingly. 
      if(error instanceof NetworkError) { 
      } else if(error instanceof ClientError) { 
      } else if(error instanceof ServerError) { 
      } else if(error instanceof AuthFailureError) { 
      } else if(error instanceof ParseError) { 
      } else if(error instanceof NoConnectionError) { 
      } else if(error instanceof TimeoutError) { 
      } 
      showProgress(false); 
      mPasswordView.setError(getString(R.string.error_incorrect_password)); 
      mPasswordView.requestFocus(); 

     } 

Und es ist das Ergebnis meines Debugger: Testerror: 400 [B @ 430b8d60

EDIT: Außerdem meine error.getMessage () ist Null.

Also ich verstehe nicht, warum meine Variable response.data nicht die Antwort von meinem Server ist.

Wenn jemand weiß, wie ich die Nachricht von meinem Server bekommen kann, wird es cool sein.

Thx,

Antwort

144

Ich habe etwas Ähnliches wie diese umgesetzt werden, und es ist relativ einfach. Ihre Log-Nachricht druckt etwas aus, was wie Kauderwelsch aussieht, weil response.data wirklich ein Byte-Array ist - kein String. Auch eine VolleyError ist wirklich nur eine erweiterte Exception, also Exception .getMessage() würde wahrscheinlich nicht zurückgeben, was Sie suchen, es sei denn, Sie überschreiben die Parsing-Methoden für die Analyse Ihrer VolleyError in Ihrer erweiterten Request Klasse. Ein wirklich grundlegender Weg, dies zu handhaben wäre, wie etwas zu tun ist:

//In your extended request class 
@Override 
protected VolleyError parseNetworkError(VolleyError volleyError){ 
     if(volleyError.networkResponse != null && volleyError.networkResponse.data != null){ 
       VolleyError error = new VolleyError(new String(volleyError.networkResponse.data)); 
       volleyError = error; 
      } 

     return volleyError; 
    } 
} 

Wenn Sie dies Ihre erweiterten Request Klassen hinzufügen, Ihre getMessage() sollte zumindest nicht null zurück. Ich mache mir normalerweise keine Gedanken darüber, da es einfach ist, alles innerhalb Ihrer onErrorResponse(VolleyError e) Methode zu machen.

Sie sollten eine JSON-Bibliothek verwenden, um die Dinge zu vereinfachen - ich verwende zum Beispiel Gson oder Sie könnten Apache JSONObject s verwenden, die keine zusätzliche externe Bibliothek benötigen sollten. Der erste Schritt besteht darin, die Antwort JSON von Ihrem Server als String (in ähnlicher Weise wie ich gerade demonstriert) zu erhalten, als nächstes können Sie es optional konvertieren in eine JSONObject (entweder Apache JSONObject s und JsonArray s oder eine andere Bibliothek Ihrer Wahl) oder analysieren Sie einfach selbst die String. Danach müssen Sie nur die Toast anzeigen.

Hier einige Beispiel-Code für den Einstieg:

public void onErrorResponse(VolleyError error) { 
    String json = null; 

    NetworkResponse response = error.networkResponse; 
    if(response != null && response.data != null){ 
     switch(response.statusCode){ 
      case 400: 
        json = new String(response.data); 
        json = trimMessage(json, "message"); 
        if(json != null) displayMessage(json); 
        break; 
      } 
      //Additional cases 
    } 
} 

public String trimMessage(String json, String key){ 
    String trimmedString = null; 

    try{ 
     JSONObject obj = new JSONObject(json); 
     trimmedString = obj.getString(key); 
    } catch(JSONException e){ 
     e.printStackTrace(); 
     return null; 
    } 

    return trimmedString; 
} 

//Somewhere that has access to a context 
public void displayMessage(String toastString){ 
    Toast.makeText(context, toastString, Toast.LENGTH_LONG).show(); 
} 
+1

erros zu behandeln Du genau schreiben :) ich die Antwort kurz vor Ihrem Beitrag gefunden. Und ich erstelle auch eine Klasse MessageServer mit 2 Attributen: Status und Nachricht wie folgt Ich benutze Gson, um meine Zeichenfolge in diese Klasse zu konvertieren und dann die Nachricht zu erhalten. – FlavienBert

+2

Hallo, Ich möchte nur hinzufügen, dass der @Override-Ansatz (den ich für sehr elegant halte) nicht flexibel ist, wenn Sie nach Netzwerkantwortdaten suchen möchten, da Sie diese Informationen verwerfen und einen neuen VolleyError mit einer String-Nachricht erstellen drin. Leider ist es nicht möglich, eine Instanz mit der ursprünglichen networkResponse und einer benutzerdefinierten Nachricht zu erstellen. – fiipi

+1

Es ist nicht unmöglich, es erfordert nur eine Unterklasse VolleyError-Implementierung, und in vielen Fällen ist die Überprüfung der Unterklasse Ihres VolleyError in onErrorResponse (VolleyError e) sowieso notwendig. – Submersed

5

diese Klasse versuchen, alle

public class VolleyErrorHelper { 
     /** 
     * Returns appropriate message which is to be displayed to the user 
     * against the specified error object. 
     * 
     * @param error 
     * @param context 
     * @return 
     */ 

     public static String getMessage (Object error , Context context){ 
      if(error instanceof TimeoutError){ 
       return context.getResources().getString(R.string.timeout); 
      }else if (isServerProblem(error)){ 
       return handleServerError(error ,context); 

      }else if(isNetworkProblem(error)){ 
       return context.getResources().getString(R.string.nointernet); 
      } 
      return context.getResources().getString(R.string.generic_error); 

     } 

     private static String handleServerError(Object error, Context context) { 

      VolleyError er = (VolleyError)error; 
      NetworkResponse response = er.networkResponse; 
      if(response != null){ 
       switch (response.statusCode){ 

        case 404: 
        case 422: 
        case 401: 
         try { 
          // server might return error like this { "error": "Some error occured" } 
          // Use "Gson" to parse the result 
          HashMap<String, String> result = new Gson().fromJson(new String(response.data), 
            new TypeToken<Map<String, String>>() { 
            }.getType()); 

          if (result != null && result.containsKey("error")) { 
           return result.get("error"); 
          } 

         } catch (Exception e) { 
          e.printStackTrace(); 
         } 
         // invalid request 
         return ((VolleyError) error).getMessage(); 

        default: 
         return context.getResources().getString(R.string.timeout); 
       } 
      } 

      return context.getResources().getString(R.string.generic_error); 
     } 

     private static boolean isServerProblem(Object error) { 
      return (error instanceof ServerError || error instanceof AuthFailureError); 
     } 

     private static boolean isNetworkProblem (Object error){ 
      return (error instanceof NetworkError || error instanceof NoConnectionError); 
     } 
+0

Diese Antwort hat eine bessere Fehlerbehandlung für 'Volley' – blueware

+0

Danke glücklich Codierung –

+0

schön, wenn Sie mit vielen Netzwerkanforderungen arbeiten :) – Josema