Is using AsyncTask still recommended for loading listView items in the background?
Asked Answered
X

3

6

Background

I've heard that there are some new solutions for loading data in the background which are more recommended than AsyncTask (like loaders).

The problem

AsyncTasks are great and easy to use. However, it has some limitations:

  1. The class itself has to be modified since it's limited by the number of pending tasks (about 256 or so). Of course, in a listView's adapter, I always cancel a task if it's not needed(for example when I need to update a view that was used for a different item).

  2. I also have to cancel them all (or handle in a different way) when the activity/fragment is being re-created.

  3. Because of 1&2, I need to manage them and have a reference to all of them

  4. AsyncTask uses a queue of tasks, and sometimes I need to use a stack instead, so I had to create my own class of AsyncTask that uses a stack instead.

The question

Are there alternatives for AsyncTask?

I know this was asked in some posts before (like here), but I was thinking if there is a new general way to load data in the background which replaces the asyncTask.

About Loaders, I think the idea is that they are used for databases and contentProviders, but can they also be used for loading (for example) data from the Internet (like images files) ?

There is also a nice sample made by google (here, called "bitmapFun"), which according to what I see uses AsyncTask (and even extend it, maybe because of the same reasons I've mentionsed) . But maybe I'm missing there something too?

Xerxes answered 17/3, 2013 at 16:24 Comment(1)
For me it would depend what I am loading in the list, but 9 out of 10 time's it'll be a backed by a CursorLoader looking at a database.Ipa
W
2

Yes.

Loaders are managed AsyncTasks. If you are not using a Loader, you are probably missing the management that they require.

AsyncTasks (and Loaders) are a pretty bad way to get stuff that is off the device. To get data from a remote server look into using an IntentService. See: https://www.youtube.com/watch?v=xHXn3Kg2IQE

Withoutdoors answered 17/3, 2013 at 16:37 Comment(5)
But IntentService handles requests one by one like in a queue, and doesn't allow to cancel them, so if the user is scrolling fast, the old items will have to be downloaded before the ones the user is seeing now.Xerxes
@androiddeveloper: Yes, but you are missing some details: 1) AsyncTasks are run in a multithreaded pool, but they are run serially (one by one!) unless you bypass the dequeue; 2a) AsyncTasks are only cancellable if you code them to be cancellable: just calling cancel doesn't necessarily stop anything; It is fairly straightforward to use the same code to allow cancelling an intent service task; 2b) Yes: Intent services are for things you want to complete, even if the Activity goes away.Withoutdoors
1.it's possible since i have the code. i had to change it anyway since the tasks number is limited. 2a. not quite, you can call cancel() and the onPostExecute won't occur, but you might also add need to put some checks sometimes in the doInBackground() function too. 2b. (why not 3?) so I end up in about the same solution as asyncTask as i have to manage all of the tasks,in the order i want to , and somehow cancel them all when i leave the activity. why would i need a service for this? just for modularity?Xerxes
@androiddeveloper: 1) yes it is possible: exactly as I said. 2a) yes, exactly as I said. 2b) No, not just for modularity. Because an AsyncTask runs in the context of an Activity which is much more ephemeral than a Service.Withoutdoors
But how would you send the data from the service to the activity (plus tell it that it's ready to be used) ? in the case of bitmaps, i think it's quite problematic, no (haven't done such a thing) ?Xerxes
A
2

Maybe you should consider reviewing your approach, the need you have for performing several updates depending on the view and cancel all the pending tasks from the previous views gives the impression that you are performing the load of data individually for every view that needs to be created.

In a list view with a list adapter, the usual approach is to load a portion of the data (either as list of ValueObject or as Cursor from multiple database rows) paginated on demand or in one goal, not item by item. So if you wish to update the next page, you basically perform one single operation, either using AsyncTask or Loaders to fetch the new items to the model then making it available for the UI to display them. This way, you will be applying MVC, and you won't have several pending tasks to cancel and control, and your structure would be more solid and easier to manage.

About the alternatives, If you're dealing with database, the most straightforward way is to use the CursorLoader, i.e. the loaders instead of AsyncTask, but if you're dealing with data that comes from the network or filesystem, you're kinda free to choose from the variety of other options available. AsyncTask is much more simpler to use, mostly recommended for simple things or one shot queries. But you can also use Loaders for such tasks as well, see AsyncTaskLoader.

Achieve answered 17/3, 2013 at 16:51 Comment(6)
If you load a lot of items at the same time, and don't show progress by displaying them, the user can think that it doesn't really load and will have to wait this whole time. Scrolling should put tasks on hold (or cancel them) as the items aren't shown anymore as new items should be shown.Xerxes
Unless if you show a progress bar for each item, e.g. like a download list, I still think you can do the updates in batch without degrading the user experience. Of course, you have to find a middle term, not load all the items at the same time, and also not load each of them individually. Find an amount that would make the UI responsive enough so the user notice the internal details.Joettajoette
i think i can think of a way to do it using this idea, but maybe you have some kind of sample you could show me that does the same thing?Xerxes
it's simple...basically the core of the idea is to build the UI completely independent of the logic or origin of the data...so to start with: define the model (ValueObjects) a simple object with getters and setters...then on your adapter you make a variable with a list of them...and ensure that the getItem fetches the object from this list, and the getView builds the view based on the object retrieved from this list...now, just build something that changes this list whenever needed, you can use a AsyncTask that fetches the data from the server, populate these objects and set them to this list.Joettajoette
after that of course, call the notifyDatasetChanged() from the Adapter...make sure that the list is only changed or accessed from the UIThread( getView() is on the UIThead) and the onPostExecute() from the AsyncTask is also on the UIThread..so you can make a call to set the new populated list from there...if you do it from another thread, you will have to deal with multithreaded conditions having to synchronized your code properly..so use this as suggested that you will have no problems. Make the prototype, evaluate and adapt any improvements you find. Best of luck!Joettajoette
what's the difference between a single long task that loads all of the images, and using multiple small tasks that do the same (yet each download its own image) ? is it better since it doesn't need to create multiple connections or close&create one all the time? BTW, there is a better way to update the list, especially if you have just a single row to update.Xerxes
D
1

AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask. See the http://developer.android.com/reference/android/os/AsyncTask.html for more info.

An alternative to asynctask is robospice.https://github.com/octo-online/robospice.

You can get started with robopice here. https://github.com/octo-online/robospice/wiki/Starter-Guide.

A sample of robospice at https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result.

Some of the features of robospice.

1.executes asynchronously (in a background AndroidService) network requests (ex: REST requests using Spring Android).

2.is strongly typed ! You make your requests using POJOs and you get POJOs as request results.

3.enforce no constraints neither on POJOs used for requests nor on Activity classes you use in your projects.

4.caches results (in Json with both Jackson and Gson, or Xml, or flat text files, or binary files, even using ORM Lite).

5.notifies your activities (or any other context) of the result of the network request if and only if they are still alive

6.no memory leak at all, like Android Loaders, unlike Android AsyncTasks notifies your activities on their UI Thread.

7.uses a simple but robust exception handling model.
Dichlorodiphenyltrichloroethane answered 17/3, 2013 at 16:40 Comment(8)
Sure it can handle anything that is done in the background, including cancelling and setting the order of the tasks (like a stack rather than like a queue) ? Downloading images content from the internet was only an example.Xerxes
github.com/octo-online/robospice/wiki/Design-of-RoboSpice.Can have multiple spice requests. A bug for multiple request was reported and solved. github.com/octo-online/robospice/issues/37. You can cancel the request.Dichlorodiphenyltrichloroethane
It seems the samples folder in their library is empty. Am I doing something wrong? I only wanted to see how it's being used...Xerxes
check the answer a link to the sample app is provided. github.com/octo-online/RoboSpice-samples. SHould find sample here.Dichlorodiphenyltrichloroethane
Which of the samples should I look at, if I want to check the general solution or the one that downloads an image content?Xerxes
i have not tried the samples. So i don't know which samples should be used.Dichlorodiphenyltrichloroethane
did u find a working sample for downloading image form server?Dichlorodiphenyltrichloroethane
A working sample is loading a tweetlist with user-avatar images, the code is here: github.com/octo-online/RoboSpice-samples/tree/release/…Liaoning

© 2022 - 2024 — McMap. All rights reserved.