I've got 2 tabs in my app, one grabs my contacts and geocodes their postcodes, the other tab plots them on a map.
The geocoding process can be quite time consuming. What is the best practice for handling such length processes?
Should I have a loading bar when the app starts and do all of the geocoding then or should I force users to click a button to do the geocoding?
You should move any operation that takes more than about 200ms onto a separate thread, so the app doesn't lock up, and then from that thread update an indicator to show the user progress.
You need to learn about the AsyncTask class, it's absolutely central to writing responsive Android apps.
http://developer.android.com/reference/android/os/AsyncTask.html
It's a pretty straightforward wrapper than makes threading easy. Remember to STOP threads when they're not needed any more, e.g. in onPause().
I tend to put AsyncTask subclasses into their own class file (not as an inner class) and pass them an activity context as a constructor parameter, so the AsyncTask thread always has easy access to the activity to update the user interface (but NOT from doInBackground).
Some limitations of AsyncTask
http://foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html
Related
I have a simple Android UI. When user clicks Button, it takes the user's location and then it goes to 4-5 websites and gets all the events in that hour. Then, according to the user's location, it compares the closest ones, and according to a radius given, it shows the event names in a new screen.
After clicking Button, it will go into another screen and will write something like searching for location or progress dialog, or location identified. After that, it'll show the events to the user. So, should I create 3 activities and 3 screens?
According to this link
how to use method in AsyncTask in android?
He says don't prefer AsyncTask for long network jobs.
I can't use location methods inside AsyncTask. Before executing I should send location as parameter. But again, computeDistance method needed. At post execute method, I can post events to new UI.
But when the user clicks these events, from onClick I can do jobs but I can't find or retrieve info of these events.
I decided to use AsyncTask after commenting somewhere here and someone answered me to use but I can't find that post.
And now i am unsure about to use or not.
I need webconnections, so I don't want to make them in main. So it is good to use AsyncTask for that but is it necessary?
This is what I would recommend:
Use AsyncTask. It will run a background thread and give you a way to display progress in the UI thread as each website is checked. This isn't a "long network job" compared to, say, streaming a video. IMHO, using a Service for something like your operation is just too heavyweight. So start out with an AsyncTask.
Once you have that, however, you will discover your next problem, which is that your web operation might take long enough that if you rotate the device, the Activity will be torn down and recreated in the new orientation. Then when your AsyncTask completes, the Activity it was supposed to call back to is no longer there. Oops, now your user doesn't get their results.
The best solution I have found for that is to use a special fragment to "host" the AsyncTask. This fragment will not create a view and use setRetainInstance(true) to keep the fragment alive during Activity re-creation.
You can read about this novel technique here: Handling Configuration Changes with Fragments
AsyncTask is an abstract class provided by Android which helps us to use the UI thread properly. This class allows us to perform long/background operations and show its result on the UI thread without having to manipulate threads.
Android implements single thread model and whenever an android application is launched, a thread is created. Assuming we are doing network operation on a button click in our application. On button click a request would be made to the server and response will be awaited. Due to single thread model of android, till the time response is awaited our screen is non-responsive. So we should avoid performing long running operations on the UI thread. This includes file and network access.
I have an activity where the user enters a value in an EditText and I search a string array that I have defined in a xml file for a match. Each time the user changes the text I look for a match. When I start this activity I load the string array resource.
Should the loading of the array and the match finding occur in a background thread?
From what I understand I can use an AsyncTask which I am familiar with or a IntentService which I have no experience with. Would IntentService be overkill? What is ideal for this operation?
In some cases it is possible to accomplish the same task with either an AsyncTask or a Service however usually one is better suited to a task than the other.
AsyncTasks are designed for once-off time-consuming tasks that cannot be run of the UI thread. A common example is fetching/processing data when a button is pressed.
Services are designed to be continually running in the background. In the example above of fetching data when a button is pressed, you could start a service, let it fetch the data, and then stop it, but this is inefficient. It is far faster to use an AsyncTask that will run once, return the data, and be done.
If you need to be continually doing something in the background, though, a Service is your best bet. Examples of this include playing music, continually checking for new data, etc.
For the most part, Services are for when you want to run code even when your application's Activity isn't open. AsyncTasks are designed to make executing code off of the UI thread incredibly simple.
You should use AutoCompleteTextView and ContentProvider to do your implementation. Save your string array in database and access them by Cursor to popup and show in AutoCompleteTextView. There is an example available in the official document.
I have a custom view on which I draw words and images of different sizes. Because I need to perform all kind of calculations on various user actions and they can last 3-4 seconds, I need to implement a way to display a progress dialog while the user is waiting.
The scenario is like this: the user adds some text and images for instance and I need to resize them until they fit the available view's space. This is all done on a method of my custom view.
What would be the best way to use threading and indeterminate progress dialog in my case?
Should I use a asynctask and call it each time an operation is made? Use simple threads? I have never used any threading in a View
You basically have two options. It's not easy to judge which is best.
AsyncTask is certainly an option here. The nice part is that it structures the synchronization with your UI for you. It passes your calculation result from doInBackground() (which runs concurrently) to onPostExecute() (which runs on the UI thread) so you can perform your calculations and update your UI safely. It also allows you to indicate background processing progress on the UI thread via the publisProgress() / onProgressUpdate() method pair.
But: The behaviour of AsyncTask has changed twice between API 1 and API 17. Depending on the Android version the device runs, by default, several AsyncTasks can run in parallel or not. You'll have to use executeOnExecutor() if this matters for you; this call was introduced for API 11 which means you'll have to deal with reflection if you want to support APIs before 11.
Your second option is to have an explicit worker Thread. The appeal of this approach is that you have a dedicated Thread for a task which frequently occurs in your app and needs to be done in background. However, you'll have to deal with all the UI synchronization issues yourself. That's not difficult if you're disciplined. If your Thread knows the View objects which need to be modified, it can use the View.post(), View.postDelayed() etc methods to schedule fragments of code which have a reference to the view and will be executed on the UI thread.
Regardless of which approach you choose, you're additionally facing two effects.
Android will run both your Thread and your AsyncTask with a background priority, which, if they are CPU intensive, will lead to a ten-fold execution time if you don't adjust it. For a detailed discussion, see my answer to AsyncTask, must it take such a performance penalty hit…?.
You need to be careful about View references in asynchronous tasks. It's posiible the View does not exist anymore because the user pressed Back or your Activity was re-created due to a configuration change aka e.g. device rotation. What this means is that you're often giving the user a way to start many of your threads by leaving and re-entering your Activity very quickly, adding more and more Threads which hold references to View objects which aren't visible any more. If you want to be clever and your computation takes long, you may (it really depends) want to re-attach your Thread to the new Activity. It's safe to ignore this for now if you make sure your Thread ends in a clean manner and frees all resources if your Activity is long gone.
This question already has answers here:
Android AsyncTask for long running operations
(4 answers)
Closed 9 years ago.
The API reference states,
AsyncTasks should ideally be used for short operations (a few seconds
at the most.)
Is the problem with a doInBackground that takes, say, 30 seconds that the thread pool might run out of threads? And if that's the reason, would it cease to be a problem if I ensure my app will never have more than one such long running doInBackground executing concurrently?
The answer given by #Walter Mundt is correct. Nevertheless, I would like to add a complement of information and give a pointer to a library that can be used for long running AsyncTask.
AsyncTasks have been designed for doing stuff in background. And, yes, it's right that if your AsyncTask lasts for two long, then you will face 2 different issues :
Activities are poorly tied to the activity life cycle and you won't get the result of your AsyncTask if your activity dies. Indeed, yes, you can but it will be the rough way.
AsyncTask are not very well documented. A naive, though intuitive, implementation and use of an asynctask can quickly lead to memory leaks.
RoboSpice, the library I would like to introduce, as proposed by #Walter Mundt, uses a background service to execute this kind of requests. It has been designed for network requests (potentially long running by nature), but it could be easily adapted to execute just long running tasks, unrelated to network. I would be glad to add a patch to it.
Here is the reason why AsyncTasks are bad for long running tasks. The following reasonning is an adaptation from exerpts of RoboSpice motivations : the app that explains why using RoboSpice is filling a need on the Android platform.
The AsyncTask and Activity life cycle
AsyncTasks don't follow Activity instances' life cycle. If you start an AsyncTask inside an Activity and you rotate the device, the Activity will be destroyed and a new instance will be created. But the AsyncTask will not die. It will go on living until it completes.
And when it completes, the AsyncTask won't update the UI of the new Activity. Indeed it updates the former instance of the activity that
is not displayed anymore. This can lead to an Exception of the type java.lang.IllegalArgumentException: View not attached to window manager if you
use, for instance, findViewById to retrieve a view inside the Activity.
Memory leak issue
It is very convenient to create AsyncTasks as inner classes of your Activities. As the AsyncTask will need to manipulate the views
of the Activity when the task is complete or in progress, using an inner class of the Activity seems convenient : inner classes can
access directly any field of the outer class.
Nevertheless, it means the inner class will hold an invisible reference on its outer class instance : the Activity.
On the long run, this produces a memory leak : if the AsyncTask lasts for long, it keeps the activity "alive"
whereas Android would like to get rid of it as it can no longer be displayed. The activity can't be garbage collected and that's a central
mechanism for Android to preserve resources on the device.
Progress of your task will be lost
You can use some workarounds to create a long running asynctask and manage its life cycle accordingly to the life cycle of the activity. You can either cancel the AsyncTask in the onStop method of your activity or you can let your async task finish, and not loose its progress and relink it to the next instance of your activity.
This is possible and we show how in RobopSpice motivations, but it becomes complicated and the code is not really generic. Moreover, you will still loose the progress of your task if the user leaves the activity and comes back. This same issue appears with Loaders, although it would be a simpler equivalent to the AsyncTask with relinking workaround mentionned above.
Using an Android service
The best option is to use a service to execute your long running background tasks. And that is exactly the solution proposed by RoboSpice. Again, it is designed for networking but could be extended to non-network related stuff. This library has a large number of features.
You can even get an idea of it in less than 30 seconds thanks to an infographics.
It is really a very very bad idea to use AsyncTasks for long running operations. Nevertheless, they are fine for short living ones such as updating a View after 1 or 2 seconds.
I encourage you to download the RoboSpice Motivations app, it really explains this in-depth and provides samples and demonstrations of the different ways to do some background operations.
If you are looking for an alternative to RoboSpice for non network related tasks (for instance without caching), you could also have a look at Tape.
I believe that AyncTasks are in general still tied to the foreground activity stack that spawned them, so that e.g. if an Activity spawns an AsyncTask, the user leaves the app, and then the OS is short of memory, it will kill the Activity's process (including the still-running AsyncTask), and just expect you to restore the state and start over if the user resumes/returns to your app.
For longer-running tasks, particularly the sort where there will only be only one or a few, you probably want a Service instead, because those can persist even when your app's UI is shut down to save memory.
Disclaimer: I haven't done Android coding in awhile, so this answer may be out of date or based on a flawed understanding of how things work. I will remove this caveat if someone with more recent experience can comment to confirm; high-rep folks are welcome to just edit this paragraph away instead if they know this is correct.
In my app, I have a class that inherits from AsyncTask and which downloads huge amounts of data from the server. I am using a ProgressBar to indicate the progress of the download.
When the user hits the HOME key, the Activity to which this AsyncTask is attached, is destroyed but, download goes on.
How can I reattach this AsyncTask and show the progress to user? I tried using onRetainNonConfigurationInstance but Android 4.0 doesn't seem to invoke this method. My application does not use Fragments API.
What I did in this situation was as follows:
I created an IntentService to handle communication with the server. This has some of the benefits of AsyncTask (e.g., worker thread), but also some benefits of a Service (available any time, from anywhere).
The IntentService can be invoked either by a user action in my main Activity, or via an inexact repeating alarm.
The data is stored in an SQLite database, fronted by a ContentProvider. I dodge the issue of when/how to create my database and tables by using an SQLiteOpenHelper and calling getWritableDatabase() from the safety of my background IntentService.
When the task is done, it posts a Notification if my main Activity is not active.
One nice thing about this arrangement is, no progress bar is necessary. In fact, no UI is necessary. The user keeps using the application while the service is running, and the UI automatically refreshes itself as new data comes into the ContentProvider. Another nice aspect of it is it's less code to write than an AsyncTask. It automatically picks up where it last left off by reading the server-side metadata of the last entry from the database and asking the user to start after that point. Since it's not tied to any Activity instance, it doesn't care about onPostExecute() or configuration changes or any of that. And you don't have to worry about single-shot execution like AsyncTask.
If there is a need to download huge amount of data in background I would use service rather then AsyncTask. There is a good presentation from Google IO about using services.
Quote from AsyncTask documentation:
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.
and
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
As I understand, you cannot proceed with your last AsyncTask.
Still, you can load your data partially and save amount of data read and then start new AsyncTask which will start from last saved point. From my point of view this is not the best idea to pause loading when activity goes to background and it is better to use service to finish what was started.
Have you considered using a service to attach your AsyncTask to? Seeing as a permanently running service would probably be the best solution for your task at hand. All you'd have to do then will be to check if the service is running and if your download is running (easily done using static boolean variables) then you just create a progress dialog using some state saving variable in your service (maybe a percentage of the total file size downloaded etc.) in the onCreate method of your main activity.