Response handling with Volley
Solution 1
But, when error occurs, I get Parse exception, when making request for JSONArray
Use JSONObject. has() and JSONObject. isNull() to check which key is present in json response before parsing json.
For Example:
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
}
Solution 2
In case of error your server should return error json with http status code 4xx. That is how you design Restful APIs. In current situation, your API is always returning 2xx which corresponds to successful API result.
If your API sends correct http response code, in this case 401 (unauthorized) or 403 (forbidden) refer here then your ErrorListener
will be called by Volley. You don't have to write parsing logic for error response in ResponseListener
. Here is a good resource for understanding rest api http status codes.
Solution 3
UPDATE RESULT SCREENSHOTS:
Success case: JSONArray
[
{
"_id": "55c06b05a3e0041a73cea744",
"name": "Category 1",
"thumbnail_data": ""
},
{
"_id": "55c06b16a3e0046108cea744",
"name": "Category 2",
"thumbnail_data": ""
}
]
Error case: JSONObject
{
"code": "failed",
"error": "error_msg"
}
In my code below, pay attention to parseNetworkResponse
.
The following is my updated answer, I have tested for both responses you provided:
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);
Hope this helps!
Solution 4
An efficient method to handle this kinda situation can be achieved through parsing JSON values using GSON and assign the key values using POJO class.
Example:
Add error scenario in both the cases like handling JSONArray or JSONObject. Please find the samples of your required POJO for your test data as follows.
Sample 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;
}
}
Sample 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;
}
}
Generating GSON from your response and handling out the both positive(success) and negativ(error) scenario as follows:
@Override
public void onResponse(JSONArray response) {
Log.d(LOG_TAG, "CCMP CATEGORY RESPONSE: " + response.toString());
if (response != null) {
//converting JSON response into GSON Format
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();
}
}
}
};
Reference links to parse into GSON from 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/
Note: To make use of GSON library in android.
Add following lines in gradle:
compile 'org.immutables:gson:2.1.0.alpha'
Solution 5
Maybe you can try this:
Use the fastjson library to convert your json string to your java object in Response.Listener like this:
Pojo pojo = JSON.parseObject(response.toString(), Pojo.class);
And your Pojo may like this:
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;
}
}
}
then what you need to do is to check if your pojo has value such as error,if error is not null ,you need to handle it .
The fastjson library has help you to avoid crash while converting.
you can find fastjson here
Nitish
Updated on July 09, 2022Comments
-
Nitish almost 2 years
I am using
Volley
in my project for handling network requests. Here is a sampleJSON
my server returnsJSON Object Response
{"code":"success", "data":{"some data"}}
JSON Array Response
{"code":"success", "data":["some data"]}
When some validation error or any other error occurs, server returns following response:
{"code":"failed", "error":"Access denied"}
The problem is with parsing data. when request is successful, in
onResponse
ofResponseListener
, I simply get the content ofdata
key. Where as, I was expecting the result same as what I posted above. I am not getting whyVolley
is returning only content ofdata
and not completeJSON
. I had usedVolley
earlier also. But never faced such type of problem.Parsing Code:
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"); }
Response on Success:
{ code: "success", data: [ { _id: "55c06b05a3e0041a73cea744", name: "Test Category 1", thumbnail_data: "", }, { _id: "55c06b16a3e0046108cea744", name: "Test Category 2", thumbnail_data: "", } ] }
In
onResponse
ofResponseListener
, I get this data:[ { _id: "55c06b05a3e0041a73cea744", name: "Test Category 1", thumbnail_data: "", }, { _id: "55c06b16a3e0046108cea744", name: "Test Category 2", thumbnail_data: "", } ]
When error occurs, server returns this response:
{"code":"failed", "error":"error_msg"}
Due to this,
Volley
throwsParseException
as it expectsJSONArray
. I need to show the error message to the user. Earlier, I was usingAsyncTask
and I handled the error there. But, withVolley
I am facing difficulty. I looked intoVolleyError
, but didn't got any clue.Update 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"); }
Update This issue was not about
Volley
. There was issue on the server end wrt gzip compression. I am going to vote for closing this question. -
Nitish over 8 yearsI should change the JSONArrayRequest to StringRequest and then handle my use case. Am I right?
-
Nitish over 8 yearsYes, I agree, but as I said, in
onResponse
I am getting only content ofdata
. So I getJSONException
there. See my updated post. -
ρяσѕρєя K over 8 years@Nitish: no need to changes just use
has
andisNull
insideonResponse
method before parsing . let me know if still have any issue -
Nitish over 8 yearsThe problem is I am making
JsonArrayRequest
. TheonResponse
ofResponseListener
only shows content of"data"
key which is an array. In case error, volley throwsParseError
as it was expecting ajson array
. I had updated my post with my parsing code. Please have a look. -
ρяσѕρєя K over 8 years@Nitish: I think u should use
JsonObjectRequest
instead ofJsonArrayRequest
-
Nitish over 8 yearsI already tried with that, volley returned
com.android.volley.ParseError: org.json.JSONException: Value [] cannot be converted to JSONObject
-
ρяσѕρєя K over 8 years@Nitish: what string getting in log from
Log.d(LOG_TAG, "CATEGORY RESPONSE: " + response.toString());
line? -
Nitish over 8 yearsFollowing is from logcat
[ { _id: "55c06b05a3e0041a73cea744", name: "Test Category 1", thumbnail_data: "", }, { _id: "55c06b16a3e0046108cea744", name: "Test Category 2", thumbnail_data: "", } ]
-
ρяσѕρєя K over 8 years@Nitish: still getting JSONArray as root item.use
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); }} }
for parsing -
Nitish over 8 yearsThat's what I was doing previously, then switched to
JsonObjectRequest
. My original method contains this code only. I need to handle the case when"code":"failed"
is returned. I'll try with switching toStringRequest
. Oh, I forgot to mention the response is gzipped, but I don't think that could be problem. -
ρяσѕρєя K over 8 years@Nitish: but in response not getting
data,status and error
keys? make sure server is returning right json which u have posted in question because json posted in comment is different -
Nitish over 8 yearsThe response in the comment is returned when everything is fine. I had posted the actual json see Response On Success in my post above. But, in
onResponse
I get what posted in my comment. -
ρяσѕρєя K over 8 years@Nitish: means u are parsing json string in OnSuccess?
-
Nitish over 8 yearsThat's the actual problem. When everything is fine, the
onResponse
only shows the array and not the whole json which I posted above. That is why I am facing problem in handling error case. Earlier also I had worked with volley but didn't faced this kind of issue. I am unable to point out what is actual problem -
Nitish over 8 yearsHi, your solution gave me idea of how to handle the issue. But I am playing around it as I have to get more clarity. I have posted the response in my post(see Response on Success). When the execution reaches
onResponse
, I get only thejson array
(i.e., array referred by"data"
), and not the complete response, that is why I cannot use the solution you posted in the update, and, that is why I am facing issue in handling error. -
BNK over 8 years@Nitish: the logic of your onResponse is the same as mine (get inner JSONArray of JSONObject). My code tested before post here. If the server response is either a JSONObject or a JSONArray, you can still use my code after UPDATE section.
-
BNK over 8 years@Nitish: I have just updated my answer. I believe it works for your case
-
BNK over 8 years@Nitish pls take a look at 2 screenshots added
-
Nitish over 8 yearsHi, Can we continue this discussion on chat?
-
Jovin over 8 yearsnot seems an issue of Volley, just try using Asynctask and check the response