2015-08-31 79 views
8

我在我的项目中使用Volley来处理网络请求。下面是一个示例JSON我的服务器返回利用Volley处理响应

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压缩问题。我将为投票结束这个问题。

+0

解析代码添加 – Nitish

+0

你得到整个响应? 'update1'后仍然有问题吗? – Blackbelt

+0

嗨..你的update1是什么? –

回答

5

But, when error occurs, I get Parse exception, when making request for JSONArray

使用JSONObject. has()JSONObject. isNull()检查哪些键存在于解析JSON之前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 
    } 
+0

我应该将JSONArrayRequest更改为StringRequest,然后处理我的用例。我对吗? – Nitish

+0

@Nitish:在解析之前,不需要改变在'onResponse'方法内使用'has'和'isNull'。让我知道如果仍然有任何问题 –

+0

问题是我正在'JsonArrayRequest'。 ResponseListener的'onResponse'只显示数组的''data''键的内容。如果发生错误,volley会抛出'ParseError',因为它期望得到一个'json数组'。我用我的解析代码更新了我的帖子。请看一看。 – Nitish

1

您可以检查代码键的值,因为它总是会提供给您回应是否会是一个失败或成功。下面是一个小片段:

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

注:更加模块化的方式来做到这一点是让一个模型类,并在其中设置你的价值观。这样你就可以在一个java对象中获得所有的值。

+0

是的,我同意,但正如我所说的,在'onResponse'我只获取'data'的内容。所以我在那里得到'JSONException'。看到我更新的帖子。 – Nitish

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

       } 
      } 

     } 
    }; 

参考链接到从解析为GSON JSON

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/

注:要使用GSON库的机器人。

添加以下行的gradle中:

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

更新结果截图:

成功案例:JSONArray

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

enter image description here

错误案例:JSONObject的

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

enter image description here

在下面我的代码,注意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); 

希望这有助于!

+0

@Nitish:我已经更新了我的回答 – BNK

+0

@Nitish:你试过了吗? – BNK

+0

嗨,你的解决方案给了我如何处理这个问题的想法。但我正在玩弄它,因为我必须更清晰。我在帖子中发布了回复(请参阅**回复成功**)。当执行达到'onResponse'时,我只得到'json数组'(即数组由'data'引用的数组),而不是完整的响应,这就是为什么我不能使用更新中发布的解决方案,以及这就是为什么我在处理错误时面临问题。 – Nitish

1

也许你可以试试这个:
使用FASTJSON库到您的JSON字符串转换成Java对象在Response.Listener这样的: 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是否有错误等值,如果错误不为null,则需要处理它。
fastjson库帮助您避免转换时崩溃。

你可以找到FASTJSON here

3

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

0

使用此代码:

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