Volley Requests is a library project which contains several request implementations and utilities based on Android's Volley library.
You can just add the dependency like below
repositories {
jcenter()
}
And then you can add the library as dependency
dependencies {
compile 'com.monits:volley-requests:1.3.2'
}
For older versions you need to use our repository.
repositories {
maven() {
url 'http://nexus.monits.com/content/repositories/oss-releases'
}
}
And for SNAPSHOTS
you need to change the url to http://nexus.monits.com/content/repositories/oss-snapshots
.
The latest current snapshot version is 1.4.0-SNAPSHOT
This is an Android library project, just like Volley.
- Clone this repository.
- Import it to your workspace.
- Add reference to your project's build path. Find how over here
We love Volley and use it extensively. In doing so, we found several patterns and types of requests coming up over and over again.
Among other things, we include:
Volley is extremely aggresive in it's caching strategies. If you are using a RESTFull API, you may have noticed in some scenarios it doesn't behave out of the box as it would be expected.
For instance, assume we make the following request:
GET /users/23
And got a cacheable entity which Volley will keep. We then want to update this user by doing:
POST /users/23
If you ever tried this, you may notice that the POST never hits the server. Volley will hit the cache and return the cached entity. This is because Volley isn't compliant with RFC 2616 (HTTP). We reached ficusk to address this issue, and provided a patch, but he insisted on keeping the current implementation (which just honors whatever the developer wants to do, and hits the cache by default).
Therefore, we decided to code a different patch, by extending Volley's Request, so we may keep using it as Volley keeps moving forward.
Every request in this library extends our base RFC-compliant request, to make sure they behave as any expirienced web developer would expect. Always.
- Uploading images? Check!
- posting JSONs? Check!
- Getting JSONs back? Check! We even use
GSON
to give back POJOs directly!
If you used ImageLoader
with any resource that may or may not
exist, you will probably know ImageLoader
don't like getting null
as the image url, and will throw a nasty NullPointerException
.
This forces developers to check every time if the resource is null and then
either call ImageLoader
or set the default placeholder manually.
We extended ImageLoader
to make nulls display the default
placeholder image and dealt with this. No conditionals bloating your code,
just tell the ImageLoader
what you want and he will get it.
Volley provides a very simple retry support, which extends timeout exponentially, and just tries over and over until it succeeds or desists.
However, we found ourselves wanting to do more. For instance, when dealing with sites that based authentication on cookies, when a request failed due to cookie or session expiration, we wanted to attempt a re-login before retrying our request, but this was not possible through the normal RetryPolicy since we would get a 302 to the login page instead of a 401 / 403.
RequeueAfterRequestDecorator
is a decorator that lets you do just
that. By being a decorator you can easily wrap this behaviour around any
existing request, making it versatile and easy to apply across any application.
RestApi is based on [Restangular] (https://github.com/mgonto/restangular) that consists
in building a request by method chaining. For now it only works with GsonRequest
,
this means that your response must be in json format.
On application startup you need to set the base url and the gson instance that you want to use throughout your app.
Rest.setBaseUrl("http://api.com:8080");
Rest.setGson(gson);
You can also optionally set an interceptor that can modify your request before it`s executed.
Rest.setInterceptor(new RequestInterceptor() {...}) //Set an interceptor
Now you are ready to create requests for your resources. Here is an example.
Suppose that you have users in your resources.
To get one user without an id (such as "yourself"), you need an url that looks something like this http://api.com:8080/me. So as you have previously set the base url, you must add the following:
Rest.one("me")
.get(User.class)
.onSuccess(successListener)
.onError(errorListener)
.onCancel(cancelListener)
.request();
To get one user by id, you simply add the id to one()
method:
Rest.one("user", id)
.get(User.class)
.onSuccess(successListener)
.onError(errorListener)
.onCancel(cancelListener)
.request();
The url generated will be http://api.com:8080/user/id.
If you need to get many users, your json response is a json array like:
[
{"firstName":"Jon", "lastName":"Snow"},
{"firstName":"Petyr", "lastName":"Baelish"},
{"firstName":"Ned","lastName":"Stark"}
]
If your response is an object that contains a json array like:
{
"response":
[
{"firstName":"Jon", "lastName":"Snow"},
{"firstName":"Petyr", "lastName":"Baelish"},
{"firstName":"Ned","lastName":"Stark"}
]
}
then you must set the elements key with the name of the object key. For this example you have to add:
Rest.setElementsKey("response");
Now that you set the elements key you are ready to create the request.
Rest.all("users")
.get(User.class)
.onSuccess(successListener)
.onError(errorListener)
.onCancel(cancelListener)
.request();
Methods POST, PATCH, PUT have the same syntax as GET, but DELETE, HEAD,
TRACE and OPTIONS have no parameters. You can also use custom verbs with
method(int method, Class clazz)
. If your response is empty, you
can pass a Void.class
zº as parameter.
Rest.one("user")
.post(Void.class)
...
If you want to add a query string to your request, add:
Rest.one("user")
.get(User.class)
.query("id", "1")
.query("timestamp", "1234")
...
.request();
or
final Map<String, String> map = ...
map.put("id", "1");
map.put("timestamp", "1234");
Rest.one("user")
.get(User.class)
.query(map);
...
.request();
If you want to add headers the syntax is the same as query string, but you
have to call headers(...)
instead of query(...)
Here is a full example of a complex request:
Rest.setBaseUrl("http://api.com:8080");
Rest.setElementsKey("users");
Rest.one("user", "12")
.all("subjects")
.get(Subject.class)
.query("year", "2015")
.query("school", "ITBA")
.onSuccess(successListener)
.onError(errorListener)
.onCancel(cancelListener)
.request();
The request url should look like this http://api.com:8080/user/12/subjects?year=2015&school=ITBA
RequestLoader
is a subclass of [Android v4 Loader] (http://developer.android.com/reference/android/support/v4/content/Loader.html)
that "binds" a Request
to an Activity's lifecycle and refreshes data periodically,
similar to [AsyncTaskLoader] (http://developer.android.com/reference/android/support/v4/content/AsyncTaskLoader.html).
If you are familiarized with Android's Loaders, you shouldn't have trouble with this one. Aside from some minor differences, its behaviour is basically the same. Here is what you need to know:
You can stop worrying about canceling your Request
, as the LoaderManager
is
attached to an Activity/Fragment's life cycle, RequestLoader
automatically cancels any
pending Requests
when your Activity/Fragment is no longer active. This will also avoid
potential problems, like unattached Views
and null pointers.
As mentioned before, it refreshes your data periodically with a delay between reloads set by an
updateThrottle
in milliseconds. Note that its default value is 0, meaning that you can
still use RequestLoader
even if you don't need constant data refreshing, as it will
load only once.You can update its value whenever you want by calling setUpdateThrottle(long delayMS)
.
Here is a brief example:
/* MyClass is the data type that the loader will refresh */
public class MyActivity extends Activity implements LoaderManager.LoaderCallbacks<MyClass> {
private RequestQueue requestQueue;
private Request request;
protected void onCreate(final Bundle savedInstanceState) {
/* Set your activity's fields */
getSupportLoaderManager().restartLoader(0, null, this);
}
public Loader<MyClass> onCreateLoader(int id, Bundle args) {
RequestLoader<MyClass> loader = new RequestLoader<MyClass>(this, request, requestQueue);
loader.setUpdateThrottle(10000l); //Set to refresh data every 10 seconds
return loader;
}
public void onLoadFinished(Loader<MyClass> loader, Cause data) {
/* What to do when loader finishes refreshing */
}
public void onLoaderReset(Loader<MyClass> loader) {
/* What to do when LoaderManager resets your Loader*/
}
}
And that's it! Now you have a full functioning loader.
We encourage you to contribute to this project!
We are also looking forward to your bug reports, feature requests and questions regarding android-volley.
Copyright 2010-2015 Monits.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License at: