So, I am working with some code that performs seemingly asynchronous tasks and uses the typical callback/listener model to receive callbacks.
My problem is that sometimes the callbacks never fire if I hold up the thread that called the operation.
Considering the following snippet of code:
doAsync(new Callback(){
// Callback here
});
The internals of doAsync() are using a handler and the main looper.
Considering I call this code from Thread A can somebody please outline the effects of blocking the Thread A right after this call.
Also, what are the effects of running the Handler on main looper and local looper will it determine the thread that the above callback is executed on? I ask this because if I block Thread A then the callback never executes.
calling in Async Task does not block the main thread...doInBackground method executes the operations in background thread...if you want to update the UI after your execution in background has completed you must override the onPostExecute() method....there are some other hooks for UI thread too like onProgressUpdate and OnCancelled in AsyncTask....please check the java doc of AsyncTask for details
Related
Here is the thing. While in UI thread, I posted an async callback in the UI thread. Is it possible to wait for the callback and execute synchronously
A good example would be to wait for WebView's evaluateJavascript while in UI thread.
//In the UI thread
webView.evaluateJavascript("javascript:.....", callback)
//Needs to be sure that the callback is completed
dosomething()
I know it's recommended to put dosomething() inside the callback. But in certain circumstance, it is not safe, like performing actions in onPause(). If you don't wait synchronously, then the view can be destroyed at any time.
override fun onPause(){
webView.evaluateJavascript("javascript:.....", callback)
doNotContinueUntilCallbackCompletes()
super.onPause()
}
Since we are in the same thread as the callback, so CountDownLatch didn't work. It blocks the entire UI thread. And since we need to access webView, so we have to make the callback in the UI thread.
So what is the correct way to do this?
Not in the general case, no. For one thing, a callback is not necessarily asynchronous. A callback could occur on the same thread. In which case waiting for it would be instant deadlock of that thread. An example of a callback that is rarely asynchronous is a visitor pattern that walks an object hierarchy. Another would be a library that posts back to the main thread when done, like Volley.
Now if you assume the callback will be called asynchronusly, then you could use a Future to wait for it- or just signal a semaphore in your callback (which is more or less what a future would do).
However, you almost never want to do this, and NEVER from the UI thread. If you did it from the UI thread the entire app would freeze. That's why you do things on other threads. Waiting for it in that case would always be a mistake. If it wasn't from the UI thread there are some use cases for it (mainly when interacting with libraries that do their own threading), but if you're going to do work on another thread and get a callback- why not just do the work now on this thread?
Also, doing it in onPause like that would probably trip a watchdog timer and cause the entire app to crash uncleanly. Lifecycle functions have a limited time to run.
I've noticed on the documentation for AsyncTask here that you can use a method called get() to retrieve your result once the work on the thread is done. The documentation says that it
Waits if necessary for the computation to complete, and then retrieves its result.
Does that mean if I have this line of code:
List<Data> data = someAsyncTask.execute.get();
in the main UI thread, does it wait for the task to complete before executing any code after it? If so, this would render the use of AsyncTask useless. What am I missing here?
Is AsyntTask.get() an alternative to using onPostExecute() to return data to the main thread? If so, is it safe? Or is its use for something completely different?
If you call AsyncTask.get() and the task is not completed, then current thread will wait (and can be interrupted).
You right, calling this method in UI thread makes AsyncTask useless. But you can call it in another thread which need result of this task for further execution.
Within an Asynctask I call a method, i mean from within doInBackgroud() { ...code goes here ... }, I call a method that is ..
A) .. within the async task class
B) .. in a different class
Is this method-call still executed in the thread of the asynctask?
I am wondering, because it is often said that "only code inside doInBackgroud() { ...code goes here ... } is executed in a different thread.
Calls made (either directly or indirectly) from within doInBackground() are automatically run in the background thread.
There are ways to force some code to run within the main UI thread (for example, see this question), but that has to done explicitly.
Yes, the method call is executed in the thread of the asynctask. The asynctask would be pretty useless if unable to invoke methods on other classes.
Furthermore, if the doInBackground method (frequently used to make web requests) would run in the main thread, the Android would throw an exception (NetworkOnMainThreadException).
I am wondering, because it is often said that "only code inside doInBackgroud() { ...code goes here ... } is executed in a different thread.
When your application is started up, a thread is created called the UI thread (also known as the ‘main’ thread). This thread dispatches all of the events to the widgets and whatnot on your application.
The AsyncTask will execute onPreExecute and onPostExecuteon the UI thread. doInBackground() on the other-hand is invoked on the background thread and will return back to the main thread once completed.
I am still confused at threads. Still I could see some answers which points to threads, UI thread, background thread, main thread etc. (mostly on AsyncTasks and updating UI from background threads etc.)
Could anyone give me a complete explanation around these or some links at least?
It would be great if the answer covers the following cases:
Which are all the threads that's involved:
When I am running an activity (setting the content view, attaching some buttons, some dialog messages)
An activity with AsyncTask
A Background Service
A HTTP call
UI thread (main thread) - it is crucial to instantiate (add) all UI elements on this thread, that is why it has a nickname UIThread
AsyncTask - has methods doInBackground, onPostExecute, etc. Sort of its own lifecycle
Background Service (service) A service runs by default in the same process as the application. in its own thread. (as pointed out by #MisterSmith) A service runs by default in the same process as the application. in its own thread. Therefore you need to use asynchronous processing in the service to perform resource intensive tasks in the background. Services which run in the process of the application are sometimes called local services.
Thought you can specify to run a Service in its own process:
Running a service in its own process will not block the application in case the service performs long running operations in its main thread. But as the services runs in its own process you need to use some interprocess communication (IPC) to communicate to your service from other parts.
HTTP call executed using HttpClient (from docs:
Thread safety of HTTP clients depends on the implementation and
configuration of the specific client.
), has to be executed on non-UI thread by using new Thread(new Runnable(...)).start();, otherwise you will get NetworkOnMainThreadException thanks to #vikram. But it seems that HttpClient.execute() method is executed in a thread, that is why it requires a handler as one of the parameters in order to pass the result to the corresponding handler (handler runs on UI thread and can update widgets (UI elements) as it is needed)
Extra:
To force something to be executed on your main thread use yourContextInstance.runOnUiThread(new Runnable(....));
In order to determine if current thread is UI(main) thread:
Looper.getMainLooper().getThread() == Thread.currentThread();
Interesting question about threads in a service:
Does a runnable in a service run on the UI thread
Why UI thread is responsible for all this?
Because UI thread is in charge of dispatching the events to the
appropriate widgets (UI elements), which includes the drawing events
Sources: this that and a little bit of that and some of that
When I am running an activity ( seting a content view , attaching some buttons, some dialog messages )
Usually only one thread (the main one, sometimes incorrectly called UI thread).
Activity - with async task
Again, by default only one (the main one). Menus and button handlers also run in the main thread. AsyncTask is a different story. It creates a worker thread (btw you should be careful not to leak it when exiting the activity).
Background Service
A service runs by default in the main thread. So do broadcast receivers. And this is why the main thread is not (only) the UI thread. Some types of services (like the popular IntentService) spawn a worker thread though.
An http Call
Is a synchronous operation, so it blocks until it completes (and this is why you should never perfom one in the main thread).
Technically speaking an application can have as many threads as it wants, they are arbitrarily created by the programmer.
However, the standard android application by default has one thread. That is the main thread, and is often referred to as the UI thread (as it is the only thread with access to the UI). By default everything happens in the main thread.
If you run an async task, different parts run in different threads, here's a basic breakdown:
onPreExecute() runs in the UI thread and is first called when you execute an async task.
doInBackground() runs in a newly spawned thread separate from the main/UI thread.
onPostExecute() runs in the UI thread after the background task returns.
A background service runs entirely separately from the application, it can run indefinitely even if the original application is destroyed.
An http call happens on whatever thread you call it on, but as a requirement of newer android API's you can no longer do any network activity from the main/UI thread. (This will actually cause an exception and terminate your application) This is to prevent slow network calls from blocking the main thread and therefore creating a choppy user experience.
Which are all the threads that's involved:
When I am running an activity (setting the content view, attaching some buttons, some dialog messages)
UI Thread or Main Thread is involved here.
An activity with AsyncTask
Both UI Thread and WorkerThread is involved.
AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). This method is used to display any form of progress in the user interface while the background computation is still executing.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
A Background Service
The IntentService class provides a straightforward structure for running an operation on a single background thread. This allows it to handle long-running operations without affecting your user interface's responsivenes
A HTTP call
NetwokrkOperation can't be executed from UI Thread ( or MainThread). So use alternatives like AsyncTask or HandlerThread
Related posts:
Handler vs AsyncTask vs Thread
Why use HandlerThread in Android
Asynctask vs Thread vs Services vs Loader
In my activity, my app downloads a list of something from a website via an Http Connection. Before this list of things is displayed on the screen, I have a Loading... TextView with a little spinning ProgressBar to indicate that the data is currnetly being downloaded.
I noticed, that if I do any type of Thread.sleep() during the process of fetching the data from the web, it freezes the spinning ProgressBar.
Even if I put the method in it's own Handler Runnable so that it's on it's own thread, the animation freezing still occurs.
Is there anything I can do about this?
Yes, use AsyncTask.
A Handler is usually attached to the UI thread. Posting Runnables to it doesn't change the fact that they will run on the UI thread.
Any application should do long running tasks on a seperate thread to the UI thread as any blocking calls will not allow the UI to update.
As the other poster said, using Runnables alone do not mean the code will be executed on a seperate thread. In this case the run() method will execute on whatever thread your Handler object was created on. Either subclass Thread or pass your runnabe to new thread object with public Thread (Runnable runnable).
Using AsyncTasks, Loaders or Threads will help.
Also read Designing for Responsiveness and Multithreading For Performance. Following the above approaches will help you avoid ANRs
The reason for such a behaviour is that:
When you do thread.sleep() inside a runnable, it is the UI thread which executes that runnable rather than the respective other thread which you created. Basically what happens is that when you post any runnable through the handler of the UI thread, UI thread will poll from its queue and execute the runnable; in this case the runnable will do sleep.
Hence no change in progress bar