【问题标题】:Response handling with VolleyVolley 的响应处理
【发布时间】:2015-08-31 04:56:12
【问题描述】:

我在我的项目中使用Volley 来处理网络请求。这是JSON我的服务器返回的示例

JSON 对象响应

{"code":"success", "data":{"some data"}}

JSON 数组响应

{"code":"success", "data":["some data"]}

当某些验证错误或任何其他错误发生时,服务器返回以下响应:

{"code":"failed", "error":"Access denied"}

问题在于解析数据。当请求成功时,在ResponseListeneronResponse 中,我只需获取data 键的内容。至于,我期待的结果与我上面发布的相同。我不明白为什么Volley 只返回data 的内容而不是完整的JSON。我之前也使用过Volley。但从来没有遇到过这样的问题。

解析代码:

private void getOnboardingCategories() {
    Response.Listener<JSONArray> responseListener = new Response.Listener<JSONArray>() {

        @Override
        public void onResponse(JSONArray response) {
            Log.d(LOG_TAG, "CATEGORY RESPONSE: " + response.toString());
            if (response != null) {
                int dataLength = response.length();
                for (int i = 0; i < dataLength; i++) {
                    JSONObject jObject = response.optJSONObject(i);
                    if (jObject != null) {
                        CategoryType2 categoryType2 = new CategoryType2();
                        categoryType2.set_id(jObject.optString("_id"));
                        categoryType2.setName(jObject.optString("name"));
                        categoryType2.setApp_icon_data(jObject.optString("thumbnail_data"));
                        categories.add(categoryType2);
                    }
                }
            }
            if (isVisible())
                sellAdapter.notifyDataSetChanged();
        }
    };

    Response.ErrorListener errorListener = new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            error.printStackTrace();
            Util.errorHandler(error, ctx);
        }
    };

    JsonArrayRequest jsonObjectRequest = new JsonArrayRequest(Method.GET, url,
            null, responseListener, errorListener);
    MyApplication.getInstance().addToRequestQueue(jsonObjectRequest, "onboarding");
}

成功响应:

{
   code: "success",
   data: [
             {
                 _id: "55c06b05a3e0041a73cea744",
                 name: "Test Category 1",
                 thumbnail_data: "",
             },
             {
                 _id: "55c06b16a3e0046108cea744",
                 name: "Test Category 2",
                 thumbnail_data: "",
             }
         ]
}

ResponseListeneronResponse 中,我得到了这些数据:

[
    {
        _id: "55c06b05a3e0041a73cea744",
        name: "Test Category 1",
        thumbnail_data: "",
    },
    {
        _id: "55c06b16a3e0046108cea744",
        name: "Test Category 2",
        thumbnail_data: "",
    }
]

发生错误时,服务器返回此响应:

{"code":"failed", "error":"error_msg"}

因此,Volley 抛出 ParseException,正如它所期望的 JSONArray。我需要向用户显示错误消息。早些时候,我使用AsyncTask 并在那里处理了错误。但是,Volley 我面临着困难。我查看了VolleyError,但没有任何线索。

更新 1

private void getOnboardingCategories() {
    showSpinnerDialog(true);
    Response.Listener<JSONObject> responseListener = new Response.Listener<JSONObject>() {

        @Override
        public void onResponse(JSONObject response) {
            Log.d(LOG_TAG, "CATEGORY RESPONSE: " + response.toString());
            hideSpinnerDialog();
            String code = response.optString("code");
            if (code.equals("success")) {
                if (response != null) {
                    JSONArray dataArray = response.optJSONArray("data");
                    int dataLength = dataArray.length();
                    for (int i = 0; i < dataLength; i++) {
                        JSONObject jObject = dataArray.optJSONObject(i);
                        if (jObject != null) {
                            CategoryType2 categoryType2 = new CategoryType2();
                            categoryType2.set_id(jObject.optString("_id"));
                            categoryType2.setName(jObject.optString("name"));
                            categoryType2.setApp_icon_data(jObject.optString("app_icon_data"));
                            categories.add(categoryType2);
                        }
                    }
                }
            }
            if (isVisible())
                sellAdapter.notifyDataSetChanged();
        }
    };

    Response.ErrorListener errorListener = new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError error) {
            error.printStackTrace();
            Util.errorHandler(error, ctx);
        }
    };

    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Method.GET, url,
            null, responseListener, errorListener);
    MyApplication.getInstance().addToRequestQueue(jsonObjectRequest, "onboarding");
}

更新 这个问题与Volley 无关。服务器端 wrt gzip 压缩存在问题。我将投票结束这个问题。

【问题讨论】:

  • 你得到了完整的回应吗? update1之后你还有问题吗?
  • 嗨..你的更新是什么?

标签: android json android-volley


【解决方案1】:

但是,当发生错误时,我在发出请求时得到 Parse 异常 对于 JSONArray

在解析 json 之前,使用 JSONObject. has()JSONObject. isNull() 检查 json 响应中存在哪个键。

例如:

JSONObject jsonObject=new JSONObject(<server_response_string>);
  if(jsonObject.has("data") && !jsonObject.isNull("data"))
  {
    // get data JSONArray from response
  }else{
     // get message using error key
   }

【讨论】:

  • 我应该将 JSONArrayRequest 更改为 StringRequest,然后处理我的用例。我说的对吗?
  • @Nitish:无需更改,只需在解析前在onResponse 方法中使用hasisNull。如果还有任何问题,请告诉我
  • 问题是我正在制作JsonArrayRequestResponseListeneronResponse 只显示 "data" 键的内容,这是一个数组。万一出错,volley 会抛出 ParseError,因为它期待 json array。我已经用我的解析代码更新了我的帖子。请看一看。
  • @Nitish:我认为你应该使用JsonObjectRequest 而不是JsonArrayRequest
  • 我已经试过了,凌空返回com.android.volley.ParseError: org.json.JSONException: Value [] cannot be converted to JSONObject
【解决方案2】:

一种处理这种情况的有效方法可以通过使用 GSON 解析 JSON 值并使用 POJO 类分配键值来实现。

示例:

在处理 JSONArray 或 JSONObject 等两种情况下添加错误场景。请找到您所需的 POJO 样本作为您的测试数据,如下所示。

示例 1

public class JSONArrayPojo
{
    private ArrayList<String> data;

    private String code;

    private String error;

   public String getError() {
      return this.error;
   }

   public void setError(String value) {
      this.error = value;
   }

    public ArrayList<String> getData ()
    {
        return data;
    }

    public void setData (ArrayList<String> data)
    {
        this.data = data;
    }

    public String getCode ()
    {
        return code;
    }

    public void setCode (String code)
    {
        this.code = code;
    }
}

示例 2

public class JSONObjectPojo
{
    private String data;

    private String code;

    private String error;

   public String getError() {
      return this.error;
   }

   public void setError(String value) {
      this.error = value;
   }

    public String getData ()
    {
        return data;
    }

    public void setData (String data)
    {
        this.data = data;
    }

    public String getCode ()
    {
        return code;
    }

    public void setCode (String code)
    {
        this.code = code;
    }

}

从您的响应中生成 GSON 并按如下方式处理正面(成功)和负面(错误)场景:

@Override
        public void onResponse(JSONArray response) {
            Log.d(LOG_TAG, "CCMP CATEGORY RESPONSE: " + response.toString());
            if (response != null) {

//将JSON响应转换为GSON格式

                JSONArraryPojo jsonArray = null;
                GsonBuilder gsonBuilder = new GsonBuilder();
                gsonBuilder.serializeNulls();
                Gson gson = gsonBuilder.create();
                jsonArray = gson.fromJson(response.toString(), JSONArraryPojo.class);

                if(jsonArray.getCode().equals("success")){

                     //process your steps if the value is success
                     Toast.makeText(this, jsonArray.getCode(), Toast.LENGTH_SHORT).show();

                }else {
                      //displaying toast when error occurs
                      Toast.makeText(this, jsonArray.getError(),    Toast.LENGTH_SHORT).show();

                }
            }

        }
    };

JSON

解析成 GSON 的参考链接

http://kylewbanks.com/blog/Tutorial-Android-Parsing-JSON-with-GSON

http://examples.javacodegeeks.com/core-java/json/json-parsing-with-gson/

http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html

http://www.mysamplecode.com/2013/07/android-json-stream-data-parsing.html

http://blog.nkdroidsolutions.com/

注意:在android中使用GSON库。

在 gradle 中添加以下行:

compile 'org.immutables:gson:2.1.0.alpha' 

【讨论】:

    【解决方案3】:

    如果发生错误,您的服务器应返回带有 http 状态代码 4xx 的错误 json。这就是你设计 Restful API 的方式。在当前情况下,您的 API 始终返回 2xx,这对应于成功的 API 结果。 如果您的 API 发送正确的 http 响应代码,在这种情况下为 401(未经授权)或 403(禁止)refer here,那么 Volley 将调用您的ErrorListener。您不必为ResponseListener 中的错误响应编写解析逻辑。这是一个很好的 resource 用于了解 rest api http 状态代码。

    【讨论】:

      【解决方案4】:

      更新结果屏幕截图:

      成功案例:JSONArray

      [
          {
              "_id": "55c06b05a3e0041a73cea744",
              "name": "Category 1",
              "thumbnail_data": ""
          },
          {
              "_id": "55c06b16a3e0046108cea744",
              "name": "Category 2",
              "thumbnail_data": ""
          }
      ]
      

      错误案例:JSONObject

      {
          "code": "failed",
          "error": "error_msg"
      }
      

      在我下面的代码中,注意parseNetworkResponse


      以下是我的更新答案,我已经测试了您提供的两个回复:

              RequestQueue queue = Volley.newRequestQueue(mContext);
              JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(0, url, new Response.Listener<JSONObject>() {
                  @Override
                  public void onResponse(JSONObject response) {
                      try {
                          if (!response.isNull("success")) {
                              JSONArray jsonArray = response.getJSONArray("success");
                              Toast.makeText(mContext, "onResponse:\n\n" + jsonArray.toString(5), Toast.LENGTH_SHORT).show();
                              if (mTextView != null) {
                                  mTextView.setText(jsonArray.toString(5));
                              }
                          } else {
                              String codeValue = response.getString("code");
                              if ("failed".equals(codeValue)) {
                                  String errorMessage = response.getString("error");
                                  Toast.makeText(mContext, "Error Message:\n\n" + errorMessage, Toast.LENGTH_SHORT).show();
                                  if (mTextView != null) {
                                      mTextView.setText("Error Message:\n\n" + errorMessage);
                                  }
                              }
                          }                        
                      } catch (JSONException e) {
                          e.printStackTrace();
                      }
                  }
              }, new Response.ErrorListener() {
                  @Override
                  public void onErrorResponse(VolleyError error) {
                      Toast.makeText(mContext, "onErrorResponse:\n\n" + error.toString(), Toast.LENGTH_SHORT).show();
                  }
              }) {
                  @Override
                  protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
                      try {
                          String jsonString = new String(response.data,
                                  HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));
                          // Check if it is JSONObject or JSONArray
                          Object json = new JSONTokener(jsonString).nextValue();
                          JSONObject jsonObject = new JSONObject();
                          if (json instanceof JSONObject) {
                              jsonObject = (JSONObject) json;
                          } else if (json instanceof JSONArray) {
                              jsonObject.put("success", json);
                          } else {
                              String message = "{\"error\":\"Unknown Error\",\"code\":\"failed\"}";
                              jsonObject = new JSONObject(message);
                          }
                          return Response.success(jsonObject,
                                  HttpHeaderParser.parseCacheHeaders(response));
                      } catch (UnsupportedEncodingException e) {
                          return Response.error(new ParseError(e));
                      } catch (JSONException e) {
                          return Response.error(new ParseError(e));
                      }
                  }
              };
      
              queue.add(jsonObjectRequest);
      

      希望这会有所帮助!

      【讨论】:

      • 嗨,您的解决方案让我知道了如何处理这个问题。但我正在玩它,因为我必须更清楚。我已在我的帖子中发布了回复(请参阅成功回复)。当执行到达onResponse时,我只得到json array(即"data"引用的数组),而不是完整的响应,这就是为什么我不能使用你在更新中发布的解决方案,也就是说为什么我在处理错误时遇到问题。
      • @Nitish:你的 onResponse 的逻辑和我的一样(获取 JSONObject 的内部 JSONArray)。我的代码在此处发布之前进行了测试。如果服务器响应是 JSONObject 或 JSONArray,您仍然可以在 UPDATE 部分之后使用我的代码。
      • @Nitish:我刚刚更新了我的答案。我相信它适用于您的情况
      • @Nitish 请看一下添加的 2 个屏幕截图
      • 嗨,我们可以在聊天中继续讨论吗?
      【解决方案5】:

      您可以检查代码键的值,因为无论响应是失败还是成功,您都可以使用它。下面是一个小sn-p:

      JSONObject jObj = new JSONObject(your_response_string);
      if(jObj.getString("code").equalsIgnoreCase("failed"))
      {
          //write code for failure....
      }
      else{
             //write code for success......
      }
      

      注意:一个更模块化的方法是创建一个模型类并在其中设置你的值。这样,您将在单个 java 对象中获取所有值。

      【讨论】:

      • 是的,我同意,但正如我所说,在onResponse 中,我只得到data 的内容。所以我在那里得到JSONException。查看我更新的帖子。
      【解决方案6】:

      也许你可以试试这个:
      使用 fastjson 库将 json 字符串转换为 Response.Listener 中的 java 对象,如下所示: Pojo pojo = JSON.parseObject(response.toString(), Pojo.class);

      你的 Pojo 可能会喜欢这样:

      public class Pojo {
      private String code;
      private String error;
      private List<Date> data;
      
      public String getCode() {
          return code;
      }
      
      public void setCode(String code) {
          this.code = code;
      }
      
      public String getError() {
          return error;
      }
      
      public void setError(String error) {
          this.error = error;
      }
      
      public List<Date> getData() {
          return data;
      }
      
      public void setData(List<Date> data) {
          this.data = data;
      }
      
      public class Data {
          public String _id;
          public String name;
          public String thumbnail_data;
      
          public String get_id() {
              return _id;
          }
      
          public void set_id(String _id) {
              this._id = _id;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public String getThumbnail_data() {
              return thumbnail_data;
          }
      
          public void setThumbnail_data(String thumbnail_data) {
              this.thumbnail_data = thumbnail_data;
          }
      }
      }
      

      那么你需要做的是检查你的pojo是否有error等值,如果error不为null,你需要处理它。
      fastjson 库可以帮助您避免在转换时崩溃。

      你可以找到fastjsonhere

      【讨论】:

        【解决方案7】:

        使用此代码:

        onResponse(JSONObject response){
            if(response.getString("code").equalIgnoreCase("success")){
                try{
                    JSONArray array = response.getJsonArray("data");
                    //do stuff with array
                }catch(JSONException e){
                    JSONObject jsonObject = response.getJsonObject("data");
                    //do stuff with object
                }
            }else{
                //show your error here
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-06-23
          • 2015-10-07
          • 1970-01-01
          • 2021-03-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多