Android: How handle message error from the server using Volley?

AndroidAndroid Volley

Android Problem Overview


I am using Volley for my Android app to fetch data from my server. It works well except when handling the error from my server. My server sends this response when there is a mistake:

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

My goal is to get the message and then display it in a Toast. I followed some sample for how to do this, but it doesn't work.

There is my error listener :

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

        }

And there the result of my debugger : testerror﹕ 400 [B@430b8d60

EDIT: Moreover my error.getMessage() is null.

So I don't understand why my variable response.data is not the response from my server.

If someone know how I can get the message from my server it's will be cool.

Thx,

Android Solutions


Solution 1 - Android

I've implemented something similar to this, and it's relatively simple. Your log message is printing out what looks like gibberish, because response.data is really a byte array - not a String. Also, a VolleyError is really just an extended Exception, so Exception.getMessage() likely wouldn't return what you are looking for unless you override the parsing methods for parsing your VolleyError in your extended Request class. A really basic way to handle this would be to do something like:

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

If you add this to your extended Request classes, your getMessage() should at least not return null. I normally don't really bother with this, though, since it's easy enough to do it all from within your onErrorResponse(VolleyError e) method.

You should use a JSON library to simplify things -- I use Gson for example or you could use Apache's JSONObjects which shouldn't require an additional external library. The first step is to get the response JSON sent from your server as a String (in a similar fashion to what I just demonstrated), next you can optionally convert it to a JSONObject (using either apache's JSONObjects and JsonArrays, or another library of your choice) or just parse the String yourself. After that, you just have to display the Toast.

Here's some example code to get you started:

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

Solution 2 - Android

try this class to handle all erros

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFlavienBertView Question on Stackoverflow
Solution 1 - AndroidSubmersedView Answer on Stackoverflow
Solution 2 - AndroidMina FawzyView Answer on Stackoverflow