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.
Related
Since in Android, every app defaults to 1 single UI thread - does that mean that all event listeners are limited to procedural execution?
(e.g. even if there are 30 buttons on the page) No matter how I click the screen, it is only possible for a single View.OnClickListener to activate at a time? Even if I click 2 buttons at the same time?
it is only possible for a single View.OnClickListener to activate at a time?
Correct.
Even if I click 2 buttons at the same time?
Correct. This is why it is very important for listeners to return quickly (sub-millisecond), so we can minimize the impact of the single-threaded UI. Move any work that might be slow — disk I/O, network I/O, long calculations, etc. — to a background thread.
Yes, and this is very useful when it comes to reasoning about your program. You never have to worry about things like the order of assignments in methods called in the UI thread, because no other method that runs in the UI thread can run until the current method exits. For example, if you start an AsyncTask in the UI thread, you know that its onPostExecute cannot run until the current method returns. If you use a handler to post something to the main looper, you know that it cannot run concurrently with any component lifecycle method. Et cetera.
I implemented a simple ListActivity with a custom ArrayAdapter. The layout contains an ImageView and a TextView. In the custom adapter's getView method I start a future to download the image concurrently at the desired position. Now, when I quickly scroll the list, the app will crash because it spawns too many download worker threads and will eventually ran out of memory.
Almost all triggered worker threads will download the image only to discard it again because the ImageView for which it was triggered will have been reused by that time, and only a few (the items to fill the full height of the device screen) are ever visible at once.
Is there a pattern to circumvent the behavior?
How about:
Custom thread pool
Override some of Android's lifecycle methods
LRU-Cache
What is the best practice to prevent the app from spawning too many unnecessary threads?
Don't spawn threads in getView- at the very least don't do one per bind. Usually you'd use a networking library such as Volley, RetroFit, etc that handles it for you. But if you want to do it yourself, go with either one download thread or a small thread pool and post requests to it. Make sure you include cancel functionality, and cancel requests that are no longer valid because they've been scrolled out of screen.
But really, just use a library that already has all of this written for you.
I'm new in Android and multithreading programming and I read in the Android.developers docs that:
It is not recommended to manipulate a view from an other thread than
the UIThread.
Ok I accepted the rule but now I would like understand why? Anyone have a simple example for me to understand why?
Thanks in advance for your help
As was stated in the comments, to avoid race conditions is part of it. Its also just a bit of bad practice. UI Thread should handle UI issues, that's what its there for. Other threads should handle other issues, that's what they're there for.
Consider the situation of having a class that modifies a TextView based on some remote query. For this you should use something like AsyncTask which allows callbacks to the UI Thread.
Now if there is ever and instance where multiple threads are working on the same UI component, what may happen is that the "wrong" (unintended) one finishes first. This is a race condition.
Also, good programming encourages a separation of concerns. You don't have the manager working on the painting that the artist is working on, so why would we imitate this behavior in software?
The upshot is: the UI should always be responsive. So if you have
some operation that will take enough time that the user will notice,
you might want to consider not running it in the UI thread. Some
common examples are network IO and database accesses. It's something
of a case-by-case basis though, so you have to make the call for
yourself a bit
A thread should be used in a long running process that would block
the UI from updating. If it's more than a second or two you
might want to put it into a background thread and notify the user
with a dialog or spinner or something. If you lock the UI thread for
more than 5 seconds the user will be prompted with a kill or wait
option by the OS.
In my app, I have to call a method which does some heavy work (I can feel device lagging). To avoid this I created an AsyncTask and it works perfectly fine.
I implemented the same thing using a Thread and here, too, it does not give any hiccup and works fine.
Now my question is which one better performance-wise - AsyncTask or Thread.
I know AsyncTask uses a threadpool to perform background tasks but in my case it will be called only once. So I don't think it will create any problems.
Can someone throw some light on it. Which one should I use for better performance?
Note: Both are being called in my Activity e.g. from UI the thread.
Can someone throw some light on it. Which one should I use for better
performance?
I think if you imagine case when you start once native Thread and AsyncTask i think that performance won't differ.
Usually native threads are used in the case if you don't want to inform potential USER with relevant information about progress in some task via UI. Here, native threads fail because they are not synchronized with UI thread and you cannot perform manipulating with UI from them.
On the other hand, AsyncTask combines background work with UI work and offers methods which are synchronized with UI and allow performing UI updates whenever you want via invoking proper methods of its lifecycle.
Generally if some task lasts more than 5 seconds you should inform USER that
"something working on the background, please wait until it will be finished"
For sure, this can be reached with both in different ways but this strongly depends on character of your task - if you need to show progress of task(how much MB is already downloaded, copying number of files and show name of each in progress dialog etc.) or you don't(creating some big data structure in "silent" only with start and end message for instance).
So and at the end of my asnwer:
Which one should I use for better performance?
Completely right answer i think you cannot get because each developer has different experiences, different coding style. How i mentioned, their performance not differ. I think that it's same(if you will read 50 MB file, it won't be faster read neither native thread nor AsyncTask). It depends again on character of task and your personal choice.
Update:
For tasks that can last much longer periods of time, you can try to think also about API tools provided by java.util.concurrent package(ThreadPoolExecutor, FutureTask etc.)
Async tasks are also threads. But they have some utility methods that make it very easy to small background tasks and get back to the UI to make changes to it. The performance would depend on your specific use case. Making absolute statements as to which one is always better would be simplistic and meaningless.
Note that the main advantage of Async tasks over threads is that Async tasks provide helper methods such as onPreExecute(), doInBackground(), onProgressUpdate() and onPostExecute() which make it very easy to perform short background tasks while also interacting with the UI (such as updating a progress bar). These kinds of methods are not available in generic Threads. Basically, Async tasks are threads with UI interaction component built in. Yes, you can use workarounds to try and update the UI from regular threads as well but Async tasks have been specifically built for this purpose and you don't have to deal with Context leaks and so on if you follow it's abstractions.
Async tasks are created to make developers' lives easier.
To sum up:
Async tasks are also threads
Async tasks make it easy to interact with UI while doing short background tasks
Neither is inherently more efficient. It depends on what you want to do.
Good rule of thumb: Use Async tasks if you need to get back to/update the UI after you are done with your background task. Use a regular thread if you don't.
The most common use of Thread are short-term tasks because they need a lot of power and tend to drain the battery and heat the phone up.
And the common use of AsyncTasks are lengthy tasks because of the same battery drain.
But a Thread is far more powerfull, because an AsyncTasks internally uses a Thread itself, but you don't have to configure that much.
ASYNC TASK and Thread do the same thing,
The difference is that you have more control on bare thread and you can benefit from the power of CPU in terms of complex implementation, the velocity of performance depends on your approach on how you implement the threading.
Depending on this article I can say that asynchronous multithreading is the fastest way to perform complex tasks.
https://blog.devgenius.io/multi-threading-vs-asynchronous-programming-what-is-the-difference-3ebfe1179a5
Regarding showing updates to user on UI thread, you can do that by posting on UI from the background thread (check UIhandler and View.Post)
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