【问题标题】:Android: How handle message error from the server using Volley?Android:如何使用 Volley 处理来自服务器的消息错误?
【发布时间】:2014-03-19 01:00:46
【问题描述】:

我正在为我的 Android 应用程序使用 Volley 从我的服务器获取数据。它运行良好,除非处理来自我的服务器的错误。当出现错误时,我的服务器会发送此响应:

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

我的目标是获取消息,然后将其显示在 Toast 中。我遵循了一些示例来了解如何执行此操作,但它不起作用。

有我的错误监听器:

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

        }

还有我的调试器的结果: testerror:400 [B@430b8d60

编辑:此外,我的 error.getMessage() 为空。

所以我不明白为什么我的变量 response.data 不是我服务器的响应。

如果有人知道我如何从服务器获取消息,那就太好了。

谢谢,

【问题讨论】:

    标签: android android-volley


    【解决方案1】:

    我已经实现了类似的东西,而且相对简单。您的日志消息打印出看起来像乱码的内容,因为response.data 实际上是一个字节数组 - 而不是String。此外,VolleyError 实际上只是扩展 Exception,因此 Exception.getMessage() 可能不会返回您要查找的内容,除非您在扩展 @987654329 中覆盖用于解析 VolleyError 的解析方法@ 班级。处理此问题的一个非常基本的方法是执行以下操作:

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

    如果您将其添加到扩展的 Request 类中,您的 getMessage() 至少不应返回 null。不过,我通常不会真正为此烦恼,因为在您的 onErrorResponse(VolleyError e) 方法中完成这一切很容易。

    您应该使用 JSON 库来简化事情——例如,我使用 Gson,或者您可以使用 Apache 的 JSONObjects,它不需要额外的外部库。第一步是获取从您的服务器发送的响应 JSON 作为 String(与我刚才演示的方式类似),接下来您可以选择将其转换为 JSONObject(使用 apache 的 JSONObjects 和JsonArrays,或您选择的其他库)或自己解析 String。之后,您只需显示Toast

    这里有一些示例代码可以帮助您入门:

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

    【讨论】:

    • 你写的正是:) 我在你的帖子之前找到了答案。我还创建了一个带有 2 个属性的 MessageServer 类:状态和消息像这样我使用 gson 将我的字符串转换为此类,然后获取消息。
    • 嗨,我只想补充一点,如果您想检查网络响应数据,您提供的 @Override 方法(我认为它非常优雅)并不灵活,因为您丢弃了该信息并创建一个带有字符串消息的新 VolleyError。不幸的是,无法使用原始 networkResponse 和自定义消息创建实例。
    • 这不是不可能的,它只需要一个 VolleyError 的子类实现,并且在许多情况下,在 onErrorResponse(VolleyError e) 中检查 VolleyError 的子类是必要的。
    • 如果我使用 json = new String(response.data); 我得到错误“字符 x 处的未终止数组”(其中 x 是字节 [] 数据中的索引)。通过传递 UTF-8 json = new String(response.data, "UTF-8"); // this works well 解决了这个错误
    • 这可行,但我认为非常重要的是要注意,当您创建带有消息的新VolleyError 时,您会丢失原始错误的其他属性,例如networkResponse。如果您不想在第二个示例中进行任何复杂的错误处理,您要么必须接受这种损失,要么创建VolleyError 的子类并覆盖其getMessage() 方法。
    【解决方案2】:

    试试这个类来处理所有的错误

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

    【讨论】:

    • 这个答案对Volley有更好的错误处理
    • 只是一个小建议:NoConnectionError 是 NetworkError 的子类,因此您的 OR 操作在 isNetworkProblem() 方法中将是多余的。您不妨检查一下 NetworkError。
    猜你喜欢
    • 2019-04-04
    • 2020-09-22
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 2016-10-03
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    相关资源
    最近更新 更多