How do I use Volley — Android Networking Library by Google
--
Volley is the best networking library I have ever seen so far. It is developed by Google but not part of native Android SDK. Read more from here in order to learn details. In this post, I will explain how I have used Volley for RESTful connection between my server and Android application.
First of all, I want to explain my JSON format provided by server side.
{result: { status: "SUCCESS",
status_code: 1,
msg: "success" },
data: { patientList: [ {
id: "551707df23f86fa507358baa",
bedNumber: 1,
name: "Fuat Basık",
age: 26,
weight: 64.5,
height: 1.75,
bloodType: "A rh+",
fileNo: "12324",
admissionDate: "date of admission" }]
}}
As you see above, there is a result and data part in JSON. Result is always available in any json response comming from server, since we want to know if our request succeed or not. Data part always correspond to predefined object in my android application.
Now we can start building our android module to talk with server. Abstraction of our ServerApi is as follows:
public interface ServerApi {
public void getAllPatients(Context context, Response.Listener<PatientListWrapper> patientListener, Response.ErrorListener errorListener);
}
Note: In this example, our abstraction depends on Volley Listener which may be changed in order to have better abstraction. Also, we can remove Context from method and have it on implementation.
Let’s implement this interface.
import android.content.Context;
import android.util.Log;
import com.android.volley.Response;
import com.mopital.doctor.core.volley.requests.BaseVolleyGETRequest;
import com.mopital.doctor.core.volley.requests.BaseVolleyPOSTRequest;
import com.mopital.doctor.core.volley.responses.Result;
import com.mopital.doctor.models.MopitalUser;
import com.mopital.doctor.models.Patient;
import com.mopital.doctor.models.wrappers.PatientListWrapper;
import org.json.JSONObject;
/**
* default implementation of server api
*/
public class DefaultServerApi implements ServerApi {
private static final String TAG = "DefaultServerApi";
private static final String BASE_API_URL = "http://*******.com/api/";
private static final String GET_ALL_PATIENTS_URL = BASE_API_URL + "patient/all";
public void getAllPatients(Context context, Response.Listener<PatientListWrapper> listener, Response.ErrorListener errorListener) {
BaseVolleyGETRequest<PatientListWrapper> getAllPatientsRequest = new BaseVolleyGETRequest<PatientListWrapper>(GET_ALL_PATIENTS_URL, PatientListWrapper.class, null, listener, errorListener);
VolleyHTTPHandler.getInstance(context).addToRequestQueue(getAllPatientsRequest);
}
}
I am able to reach my ServerAPI anywhere in the application. I have an extra class to reach api that uses provider pattern.
VolleyHttpHandler is taken from Volley Documentation. It is recommended way of implementing a Volley singleton (See here). In this example, VolleyHttpHandler is a singleton class that contains a request queue for volley requests. As you see, parseNetworkResponse method is quite clean, thanks to generic volley request wrapper(BaseVolleyGETRequest) that I have coded. The trick is BaseVolleyGETRequest class. It is using generics so that I can easily specify which class should be used for Json mapping. In this example, I tell that I want to map coming json object to PatientListWrapper that is a data class with list of Patient.
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import java.util.Map;
import com.mopital.doctor.core.ResultCode;
import com.mopital.doctor.core.volley.responses.Result;
import com.mopital.doctor.core.volley.responses.VolleyFailWrapper;
/**
* Created by ahmetkucuk on 01/03/15.
*/
public class BaseVolleyGETRequest<T> extends Request<T> {
private final Gson gson = new Gson();
private final Class<T> clazz;
private final Map<String, String> headers;
private final Response.Listener<T> listener;
public BaseVolleyGETRequest(String url, Class<T> clazz, Map<String, String> headers,
Response.Listener<T> listener, Response.ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
@Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String responseStr = new String(response.data);
JsonParser parser = new JsonParser();
JsonObject jsonObject = parser.parse(responseStr).getAsJsonObject();
Result result = gson.fromJson(jsonObject.get("result"), Result.class);
T data = gson.fromJson(jsonObject.get("data"), clazz);
if(ResultCode.fromInt(result.getStatus_code()) != ResultCode.SUCCESS)
return Response.error(new VolleyFailWrapper(result));
return Response.success(data,HttpHeaderParser.parseCacheHeaders(response));
} catch (JsonSyntaxException e) { return Response.error(new ParseError(e));}
}
}
BaseVolleyGETRequest class allow me to define the type that I should use while deserialising Json data into Java Object. This helps me to parse coming data very easily. I also code BaseVolleyPOSTRequest for post requests.
Since I know all Json responses have result data, I automatically parse result section of Json data and check if it succeed. If it is not succeed, I use Volley Fail Wrapper Class that I write for custom failures, which wraps my Result object.
import com.android.volley.VolleyError;
/**
* Created by ahmetkucuk on 01/03/15.
*/
public class VolleyFailWrapper extends VolleyError {
private Result result;
public VolleyFailWrapper(Result r) {this.result = r;}
public Result getResult() {return result;}
}
As a result, Volley is very nice and easy library to use for Restful networking besides File transportation which might be a topic for another post. This example is clean and structured way of usage for this library. However, I would like to here your suggestions for improvements.