Volley or Service with cursor loader
Asked Answered
L

4

12

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?

Labuan answered 4/8, 2013 at 14:14 Comment(0)
S
24

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

Statis answered 21/8, 2013 at 22:2 Comment(2)
Could you briefly explain how Loaders and Content providers are factored into this. In my case, I have a simple API calls that loads data. I do not need data when offline or to store any data in my database. Are the 2 things necessary given I am using volley?Insulation
Well a cursor is created via content providers and loaders. So that's my contained in my hybrid approach. Now what you're saying is that you application is very simple, so go ahead and just use volley. But again, I did provide a caveat, that it would be very surprising if you were able to offer as consistent / fast experience if you didn't create a persistence layer. The layer isn't there for "offline" support, it's there for you to store the data when you say, have an activity transition, rotate the device orientation, go back up the activity stack.Highsounding
D
11

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.

Debutant answered 20/8, 2013 at 12:46 Comment(3)
I don't understand the justification of using a service and volley together. You can, but since the queue is really homed in the Application class, why bother with the service?Highsounding
"the queue is really homed in the Application class" what is that supposed to mean? The queue can live in Service as well. Well as an example of justification I will repeat my words that by using a service you explicitly declare you are doing a background work and asking a system to keep your process alive for longer. Service has other perks, for example you can move it to a separate process if you want to with one line in manifest. Service is a specifically designed component for heavy background work so why not use it?Debutant
Well I guess it doesn't really live anywhere but I fire up all singletons from the Application class and any services or activities that need it grab it from the Application class. "by using a service you explicitly declare you are doing a background work and asking a system to keep your process alive for longer." That's a good a good specific reason / use case, thank you! My personal advocacy for not using something is in general, if you don't need it, you don't need it.Highsounding
B
1

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

Bonner answered 17/9, 2013 at 19:26 Comment(2)
That's a novel way to handle it. perhaps abstracting the functionality behind a loader will make it feel a little more conventional?Highsounding
This is very old now. My current way of handling it: RxJava with Observable that aggregates http stream and db stream. Much cleaner :)Bonner
H
0

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.

Hargrave answered 4/8, 2013 at 18:21 Comment(1)
The caveat to "downloading stuff" is that the full response is buffered before anything can happen to the data in volley. So larger files are pretty resource intensive, and some types of files you want the ability to stream. Eg. if a web browser waited for the full complete download of html before beginning parsing, it would be significantly slower. Eg. Graphics or video that have some value in being streamed, like progressive images or animated gifs, webmHighsounding

© 2022 - 2024 — McMap. All rights reserved.