From:http://www.androidhive.info/2014/05/android-working-with-volley-library-1/
Android volley is a networking library was introduced to make networking calls much easier, faster without writing tons of code. By default all the volley network calls works asynchronously, so we don’t have to worry about using asynctask anymore.
Volley comes with lot of features. Some of them are
1. Request queuing and prioritization
2. Effective request cache and memory management
3. Extensibility and customization of the library to our needs
4. Cancelling the requests
Before getting into this tutorial, I suggested you to view the below presentation by Ficus Kirkpatrick at Google I/O to get an overview of volley.
1. In Android Studio, create a new project by navigating to File ⇒ New Project and fill all the required details. When it prompts to select a default activity, select Blank Activity and proceed.
2. Create two packages named app and utils to keep the project organized.
3. Open build.gradle and add volley support by adding
compile ‘com.mcxiaoke.volley:library-aar:1.0.0’ under dependencies section.
dependencies {
compile fileTree(dir:
'libs'
, include: [
'*.jar'
])
compile
'com.android.support:appcompat-v7:22.2.0'
compile
'com.android.volley:volley:1.0.0'
}
|
The best way to maintain volley core objects and request queue is, making them global by creating a singleton class which extends Application object.
4. Under utils package, create a class named LruBitmapCache.java and paste the below code. This class is required to handle image cache.
package
info.androidhive.volleyexamples.volley.utils;
import
com.android.volley.toolbox.ImageLoader.ImageCache;
import
android.graphics.Bitmap;
import
android.support.v4.util.LruCache;
public
class
LruBitmapCache
extends
LruCache
implements
ImageCache {
public
static
int
getDefaultLruCacheSize() {
final
int
maxMemory = (
int
) (Runtime.getRuntime().maxMemory() /
1024
);
final
int
cacheSize = maxMemory /
8
;
return
cacheSize;
}
public
LruBitmapCache() {
this
(getDefaultLruCacheSize());
}
public
LruBitmapCache(
int
sizeInKiloBytes) {
super
(sizeInKiloBytes);
}
@Override
protected
int
sizeOf(String key, Bitmap value) {
return
value.getRowBytes() * value.getHeight() /
1024
;
}
@Override
public
Bitmap getBitmap(String url) {
return
get(url);
}
@Override
public
void
putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}
|
5. Under app package, create a class name AppController.java and extend the class from Application and add the following code.
package
info.androidhive.volleyexamples.app;
import
info.androidhive.volleyexamples.volley.utils.LruBitmapCache;
import
android.app.Application;
import
android.text.TextUtils;
import
com.android.volley.Request;
import
com.android.volley.RequestQueue;
import
com.android.volley.toolbox.ImageLoader;
import
com.android.volley.toolbox.Volley;
public
class
AppController
extends
Application {
public
static
final
String TAG = AppController.
class
.getSimpleName();
private
RequestQueue mRequestQueue;
private
ImageLoader mImageLoader;
private
static
AppController mInstance;
@Override
public
void
onCreate() {
super
.onCreate();
mInstance =
this
;
}
public
static
synchronized
AppController getInstance() {
return
mInstance;
}
public
RequestQueue getRequestQueue() {
if
(mRequestQueue ==
null
) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return
mRequestQueue;
}
public
ImageLoader getImageLoader() {
getRequestQueue();
if
(mImageLoader ==
null
) {
mImageLoader =
new
ImageLoader(
this
.mRequestQueue,
new
LruBitmapCache());
}
return
this
.mImageLoader;
}
public
void
addToRequestQueue(Request
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
public
void
addToRequestQueue(Request
req.setTag(TAG);
getRequestQueue().add(req);
}
public
void
cancelPendingRequests(Object tag) {
if
(mRequestQueue !=
null
) {
mRequestQueue.cancelAll(tag);
}
}
}
|
6. Now open AndroidManifest.xml and add this singleton class in
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
manifest
xmlns:android
=
"http://schemas.android.com/apk/res/android"
package
=
"info.androidhive.volleyexamples"
android:versionCode
=
"1"
android:versionName
=
"1.0"
>
<
uses-sdk
android:minSdkVersion
=
"8"
android:targetSdkVersion
=
"19"
/>
<
uses-permission
android:name
=
"android.permission.INTERNET"
/>
<
application
android:name
=
"info.androidhive.volleyexamples.app.AppController"
android:allowBackup
=
"true"
android:icon
=
"@drawable/ic_launcher"
android:label
=
"@string/app_name"
android:theme
=
"@style/AppTheme"
>
application
>
manifest
>
|
Now the primary setup required for volley is done. Let’s move on to individual options those volley provides to make the http requests.
Volley provides an easy to make json requests. If you are expecting json object in the response, you should use JsonObjectRequest class or if the response is json array, JsonArrayRequest class should be used.
2.1 Making json object request
Following code will make a json object request where the json response will start with object notation ‘{‘
// Tag used to cancel the request
String tag_json_obj =
"json_obj_req"
;
String url =
"http://api.androidhive.info/volley/person_object.json"
;
ProgressDialog pDialog =
new
ProgressDialog(
this
);
pDialog.setMessage(
"Loading..."
);
pDialog.show();
JsonObjectRequest jsonObjReq =
new
JsonObjectRequest(Method.GET,
url,
null
,
new
Response.Listener
@Override
public
void
onResponse(JSONObject response) {
Log.d(TAG, response.toString());
pDialog.hide();
}
},
new
Response.ErrorListener() {
@Override
public
void
onErrorResponse(VolleyError error) {
VolleyLog.d(TAG,
"Error: "
+ error.getMessage());
// hide the progress dialog
pDialog.hide();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj);
|
2.2 Making json array request
Following will make json array request where the json response starts with array notation ‘[‘
// Tag used to cancel the request
String tag_json_arry =
"json_array_req"
;
String url =
"http://api.androidhive.info/volley/person_array.json"
;
ProgressDialog pDialog =
new
ProgressDialog(
this
);
pDialog.setMessage(
"Loading..."
);
pDialog.show();
JsonArrayRequest req =
new
JsonArrayRequest(url,
new
Response.Listener
@Override
public
void
onResponse(JSONArray response) {
Log.d(TAG, response.toString());
pDialog.hide();
}
},
new
Response.ErrorListener() {
@Override
public
void
onErrorResponse(VolleyError error) {
VolleyLog.d(TAG,
"Error: "
+ error.getMessage());
pDialog.hide();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(req, tag_json_arry);
|
StringRequest class will be used to fetch any kind of string data. The response can be json, xml, html or plain text.
// Tag used to cancel the request
String tag_string_req =
"string_req"
;
String url =
"http://api.androidhive.info/volley/string_response.html"
;
ProgressDialog pDialog =
new
ProgressDialog(
this
);
pDialog.setMessage(
"Loading..."
);
pDialog.show();
StringRequest strReq =
new
StringRequest(Method.GET,
url,
new
Response.Listener
@Override
public
void
onResponse(String response) {
Log.d(TAG, response.toString());
pDialog.hide();
}
},
new
Response.ErrorListener() {
@Override
public
void
onErrorResponse(VolleyError error) {
VolleyLog.d(TAG,
"Error: "
+ error.getMessage());
pDialog.hide();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
|
It is obvious that sometimes we need to submit request parameters while hitting the url. To do that we have to override getParams() method which should return list of parameters to be send in a key value format.
If you observe below example, I am submitting name, email and password as request parameters.
// Tag used to cancel the request
String tag_json_obj =
"json_obj_req"
;
String url =
"http://api.androidhive.info/volley/person_object.json"
;
ProgressDialog pDialog =
new
ProgressDialog(
this
);
pDialog.setMessage(
"Loading..."
);
pDialog.show();
JsonObjectRequest jsonObjReq =
new
JsonObjectRequest(Method.POST,
url,
null
,
new
Response.Listener
@Override
public
void
onResponse(JSONObject response) {
Log.d(TAG, response.toString());
pDialog.hide();
}
},
new
Response.ErrorListener() {
@Override
public
void
onErrorResponse(VolleyError error) {
VolleyLog.d(TAG,
"Error: "
+ error.getMessage());
pDialog.hide();
}
}) {
@Override
protected
Map
Map
new
HashMap
params.put(
"name"
,
"Androidhive"
);
params.put(
"password"
,
"password123"
);
return
params;
}
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj);
|
Just like adding request parameters, to send request headers, we have to override getHeaders(). In below example I am sending Content-Type and apiKey in request headers.
// Tag used to cancel the request
String tag_json_obj =
"json_obj_req"
;
String url =
"http://api.androidhive.info/volley/person_object.json"
;
ProgressDialog pDialog =
new
ProgressDialog(
this
);
pDialog.setMessage(
"Loading..."
);
pDialog.show();
JsonObjectRequest jsonObjReq =
new
JsonObjectRequest(Method.POST,
url,
null
,
new
Response.Listener
@Override
public
void
onResponse(JSONObject response) {
Log.d(TAG, response.toString());
pDialog.hide();
}
},
new
Response.ErrorListener() {
@Override
public
void
onErrorResponse(VolleyError error) {
VolleyLog.d(TAG,
"Error: "
+ error.getMessage());
pDialog.hide();
}
}) {
/**
* Passing some request headers
* */
@Override
public
Map
throws
AuthFailureError {
HashMap
new
HashMap
headers.put(
"Content-Type"
,
"application/json"
);
headers.put(
"apiKey"
,
"xxxxxxxxxxxxxxx"
);
return
headers;
}
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj);
|
Volley introduced custom image view element called NetworkImageView to display the images from an URL. Previously downloading images and maintaining caches is a tough job. Now using volley this can be done with very few lines of code.
6.1 Loading image in NetworkImageView
Following will load an image from an URL into NetworkImageView.
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
// If you are using NetworkImageView
imgNetWorkView.setImageUrl(Const.URL_IMAGE, imageLoader);
|
6.2 Loading image in ImageView
If you want to load image into ImageView instead of NetworkImageView, you can do that too as mentioned below. Here we will have success and error callbacks, you have to take appropriate action depending on the need. Below in onResponse() method using response.getBitmap() I am loading bitmap into an ImageView.
ImageLoader imageLoader = AppController.getInstance().getImageLoader();
// If you are using normal ImageView
imageLoader.get(Const.URL_IMAGE,
new
ImageListener() {
@Override
public
void
onErrorResponse(VolleyError error) {
Log.e(TAG,
"Image Load Error: "
+ error.getMessage());
}
@Override
public
void
onResponse(ImageContainer response,
boolean
arg1) {
if
(response.getBitmap() !=
null
) {
// load image into imageview
imageView.setImageBitmap(response.getBitmap());
}
}
});
|
6.3 Defining placeholder image and error image
Here is another way of displaying image into ImageView with the option of placeholder for loader and error. The loader placeholder will be displayed until the image gets downloaded. If the image fails to download, the error placeholder will be displayed.
// Loading image with placeholder and error image
imageLoader.get(Const.URL_IMAGE, ImageLoader.getImageListener(
imageView, R.drawable.ico_loading, R.drawable.ico_error));
|
Volley comes with powerful cache mechanism to maintain request cache. This saves lot of internet bandwidth and reduces user waiting time. Following are few example of using volley cache methods.
7.1 Loading request from cache
Like below you can check for a cached response of an URL before making a network call.
Cache cache = AppController.getInstance().getRequestQueue().getCache();
Entry entry = cache.get(url);
if
(entry !=
null
){
try
{
String data =
new
String(entry.data,
"UTF-8"
);
// handle data, like converting it to xml, json, bitmap etc.,
}
catch
(UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
else
{
// Cached response doesn't exists. Make network call here
}
|
7.2 Invalidate cache
Invalidate means we are invalidating the cached data instead of deleting it. Volley will still uses the cached object until the new data received from server. Once it receives the response from the server it will override the older cached response.
AppController.getInstance().getRequestQueue().getCache().invalidate(url,
true
);
|
7.3 Turning off cache
If you want disable the cache for a particular url, you can use setShouldCache() method as below.
// String request
StringRequest stringReq =
new
StringRequest(....);
// disable cache
stringReq.setShouldCache(
false
);
|
7.4 Deleting cache for particular URL
Use remove() to delete cache of an URL.
AppController.getInstance().getRequestQueue().getCache().remove(url);
|
7.5 Deleting all the cache
Followoing will delete the cache for all the URLs.
AppController.getInstance().getRequestQueue().getCache().clear(url);
|
If you notice addToRequestQueue(request, tag) method, it accepts two parameters. One is request object and other is request tag. This tag will be used to identify the request while cancelling it. If the tag is same for multiple requests, all the requests will be cancelled. cancellAll() method is used to cancel any request.
8.1 Cancel single request
Following will cancel all the request with the tag named “feed_request”
String tag_json_arry =
"json_req"
;
ApplicationController.getInstance().getRequestQueue().cancelAll(
"feed_request"
);
|
8.2 Cancel all requests
If you don’t pass any tag to cancelAll() method, it will cancel the request in request queue.
ApplicationController.getInstance().getRequestQueue().cancelAll();
|
If you are making multiple request at the same time, you can prioritize the requests those you want be executed first. The priory can be Normal, Low, Immediate and High.
private
Priority priority = Priority.HIGH;
StringRequest strReq =
new
StringRequest(Method.GET,
Const.URL_STRING_REQ,
new
Response.Listener
@Override
public
void
onResponse(String response) {
Log.d(TAG, response.toString());
msgResponse.setText(response.toString());
hideProgressDialog();
}
},
new
Response.ErrorListener() {
@Override
public
void
onErrorResponse(VolleyError error) {
VolleyLog.d(TAG,
"Error: "
+ error.getMessage());
hideProgressDialog();
}
}) {
@Override
public
Priority getPriority() {
return
priority;
}
};
|
As of now volley doesn’t provided any native classes to make XML requests, but this can be achieved by building a custom xml wrapper class by utilizing volley’s customization capabilities. The part of writing xml parser using volley will be covered in upcoming tutorial.
I have given a sample project covering the scenarios explained in this tutorial. Download it and let’s discuss the queries if you have any in the comments section