Question

I almost always use a Service when I download data from a web service. I store the result in a database and displays the result in my view using a cursor loader. But after Google released the network library Volley I have become a bit confused. The volley library uses async tasks instead of a Service and it doesn't use cursors. I thought that I was supposed to avoid async task and store my data in a database so that I could handle orientation changes properly - without loosing data and having the need to download the data again.

So my question is, when should I use Volley instead of my own download strategy?

Was it helpful?

Solution

Traditional Arch

Personally, in the past I've found using a service to be cumbersome to implement but at the end of the day was well structured and was a good consistent experience. But threading performance... hard to manage.

Service query - > database load -> notify

UI initiate query and cursor load - > update ui.

Volley Only

With volley it is tempting to skip the entire component that was previously handled within a service and database.

UI Volley request -> Volley response -> update ui

However, this falls apart quite quickly depending on the data you are trying to display and perhaps even the server you are querying against for any of the following requirements

  • the data being displayed is not fully described by the same URL (eg. pages)

The user might scroll down and pull in more pages. However when the user comes back to the activity or even simply rotates, the call to Volley will return a result for only the initial page unless you specifically remember all of the other queries that the page consists. This becomes a lot of work for an architecture that is meant to be more convenient. Or even a page that is slightly different, this can be an inconsistent experience to the user if all they did was rotate the phone.

  • the data has to be modified

It's easier to apply the change locally and then apply to the server whenever. With volley only, you would have to do an REST update and requery (of all previous queries) synchronously.

  • Speed and persistence

Volley is really fast. However, it lacks any persistence apart from cache hits where available which can depend on the server you are querying. Aggressive caching can even wreak havoc on your app with stale data. Pulling from a local database provides a consistent and fast experience when navigating through multiple activities that might actually be referencing data in past queries. A pure volley experience might require you to query for data you technically already have from previous queries but have no central data store to get that data from.

Hybrid Volley and Cursors

These days I actually skip the service part, but everything else remains from the traditional arch

UI initiate volley query and cursor load - > update ui

Volley query -> update database -> notify

Also, there is nothing stopping you from having the ui ping a service and then the service uses volley... It will look more traditional there might be value moving more control logic to somewhere more centralised, but that fact that it's run from within a "service" actually offers no technical advantage.

Summary

I hope that helps. Basically, don't attempt to go volley only, I tried and it would be a very specific and simple app if that's what worked for you and hopefully I've identified the main pitfalls.

Also, I found the same pitfalls with robospice despite it being in a service... But... YMMV

OTHER TIPS

Volley is just a helper layer for communicating with server that manages threads and stuff. Yes, it already implements nice threading caching and stuff. But you don't have to use it in your Activities. I would even say you shouldn't. We all know that service is in fact the place to do any background network work. It is designed to survive configuration changes and is a natural way for your application to declare it DOES work in background and should be taken with extra care by the system.

Imagine, there was no Volley. What would you do? I bet you would imlement your threading support in a service, right (we all know Services work on main thread)? It may be as simple as an IntentService, which is a single static worker thread and a handler for it. Or you may go fancy and use ExecutorService to have a pool of threads. Or you can go crazy and start a new Thread() each time in onStartCommand(). Whatever suits your needs and taste.

So I prefer looking at Volley as just another way of accomplishing this tasks. This time you don't need to do any work with threads yourself, you just have Volley do it for you.

So the bottom line is use Volley AND Service together.

I encountered the same issue, and I didn't like to have separated processes for local and network request. I extended the Volley library to include the process of having a local database request (for offline content) and a network request.

Basically I have a CompleteRequest that will return:

  • an intermediate response, which can be either from http cache or from local database (run in parallel, the fastest that finishes return a result, the second one is ignored)
  • a final response, which will be from the network (or an error)

The request looks like:

public class SampleRequest extends CompleteRequest<Object> {

    public SampleRequest(int method, String url, ResponseListener<Object> responseListener, Response.ErrorListener errorListener) {
        super(method, url, responseListener, errorListener);
    }

    @Override
    protected Object getLocalResponse() {
        // query your local database for example
        // return the result or null if there is no result from database
        return new Object();
    }

    @Override
    public void saveNetworkResponseToLocal(Object response) {
        // save the network response to the local database
        // next time the request is performed the local response will return the result faster than the network request
    }

    @Override
    protected BallResponse<Object> parseBallNetworkResponse(NetworkResponse response) {
        // parse the result from the network request, in the same way than with volley
        return Response.success(new Object());
    }
}

And you perform the request like that, with the response listener that includes the intermediate and the final response:

mRequestQue.add(new SampleRequest(Request.Method.GET, "http://some.url", new ResponseListener<Object>() {
    @Override
    public void onIntermediateResponse(Object response, BallResponse.ResponseSource responseSource) {
        // intermediate response, such as from local database or soft cached network response
    }

    @Override
    public void onFinalResponse(Object response, BallResponse.ResponseSource responseSource) {
        // final response, which is the network response
    }

    @Override
    public void onFinalResponseIdenticalToIntermediate(BallResponse.ResponseSource responseSource) {
        // final response is identical to intermediate one
        // happens when intermediate is from soft cache and network response is identical (not modified)
    }

}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        // network response is an error, in the same way than with volley
    }
}
));

It's still in an early stage of development, but I'm using it in several apps and it works nice. I wrote a quick readme with examples and there is sample project that can help.

You can check it out at https://github.com/lukaspili/Volley-Ball

Always use volley for downloading stuff. If you additionally need to keep data in db you still can use it. Just rethink your architecture. Volley is a network tool, nothing more than that.

Oh and volley doesn't use AsyncTasks.

Volley is meant to provide a more convenient way to asynchronously perform network requests. It doesn't require you to subclass a Service or an AsyncTask, and its syntax is very straight forward for any experienced developer.

As stated above, this is entirely a convenience. If you have a mechanism that works well, then by all means use it. If you find yourself rewriting code constantly that follows your existing model, you may want to look into a reusable library, such as Volley or droidQuery.

There is no right or wrong answer. There may, however, be a better or worse factor. The main comparison here is speed. Volley boasts fast speeds, and plans to support OKHTTP soon, as well as to become part of the Android SDK (or a compatibility pack), continuing to grow with the Android platform. If these things are important to you, then maybe you should switch for future applications (unless you have noticeable lag in current applications, I would struggle to see a point to changing working code).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top