Android - Thread.sleep and Handler.postDelayed() freezes animated UI elements - java

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

Related

Is it possible to wait for a callback in the same thread?

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.

Understanding UI thread

For example, there are a lot of tasks are posted to UI thread as follows.
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
#Override
public void run() {
// Some logic to display/update something in UI
}
}, 5000);
What happens to these tasks when the android application went to the background?
Will these tasks be processed even in the background? Will the complete UI thread be suspended in the background? Or? All the tasks posted to UI thread are suspended?
What happens to UI thread when there are no tasks posted to it after the activity is completely loaded? Will it be suspended, if there are no tasks are in the Looper?
Thanks in advance.
Let's get's dirty with few terms first.
Handler:
A Handler allows communicating back with UI thread from other
background thread. This is useful in android as android doesn’t allow
other threads to communicate directly with UI thread.
In technical terms, it is a way to post Messages or runnable to your associated thread message queue.
so in total there are two task performed by handler
to schedule messages and runnables to be executed as some point in the future; and
to enqueue an action to be performed on a different thread than your own.
so how to schedule one
post(Runnable),
postAtTime(Runnable, long),
postDelayed(Runnable, Object, long),
sendEmptyMessage(int),
sendMessage(Message),
sendMessageAtTime(Message, long),
sendMessageDelayed(Message, long).
Looper:
Whatever I mentioned earlier is supported by Looper It has a loop()
method which keeps running and listening for the new messages, main thread has one running all the time so you can receive messages from another thread to this thread, if you are creating your own thread and want to listen then don't forget to call prepare() in the thread that is to run the loop.
A simple example
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
so now to answer your questions:
1: Things(Threads and so Looper and Handler) keep running until it gets finished by the user or killed by the system.
2: A looper has a loop() method that will process each message in the queue, and block when the queue is empty.
3: In case of updating the UI from background thread make sure app is in the foreground or terminate the background thread in onDestroy() you can quit the looper processing messages using handler.getLooper().quitSafely() or handler.looper.quit() if the handler is attached to the main thread.
It's recommended in case of orientation change or other configuration changes make sure to terminate the background thread.
There are many answers concerning the case. I will try to answer exactly to the questions.
What happens to these tasks when android application gone to background?
Nothing is interrupted. Handler will post a Message on MessageQueue on the specified time (unless the hosting process is killed).
Will these tasks are processed even in the background?
From the standpoint of Handler: it doesn't know whether the app is in foreground or background. All it knows, is that it should post a Message some time later.
Will the complete UI thread be suspended in background? Or? All the tasks posted to UI thread are suspended?
What happens to UI thread when there are no tasks posted to it after the activity is completely loaded? Will it be suspended, if there are no tasks are in the Looper?
UI thread won't be "suspended" in any case (unless the hosting process is killed). It's just that it will be idle as a result of MessageQueue being empty - thus no job is needed to be done.
As a side note, refrain from performing UI related actions when app goes to background, because the state of view hierarchy won't be saved correctly. Assume you have performed textView.setText("bob") at a time, when app is in background. Now, the state of this TextView won't be saved, because onSaveInstanceState() has already been executed and won't be executed again, thus if process of the app is killed and recreated (i.e. as a consequence of system resources shortage), then the activity will be restored with a state that it had possessed when onSaveInstanceState() was called. Now user won't see "bob".
You can cancel the scheduled event using Handler#removeCallbacks() API.
UI thread is also known as the Main thread, it's a thread launched by default when you open your application and where all your interactions happen unless you offload them to some other thread. It's not dependent on the visibility of the app, it's running as long as the app lives. It's not suspended by the system.
What happens to UI thread when there are no tasks posted to it after the activity is completely loaded? Will it be suspended, if there are no tasks are in the Looper?
Let's start with the Looper concept. It's very important for understanding how UI thread is working. Looper is a thing that loops in a given thread and handles incoming messages, when there are no tasks it's looping and waiting for new tasks, so, answering your last question, the thread will not be suspended. Looper is designed to keep the thread alive even when there are no tasks. UI thread in Android has it's own Looper by default.
What happens to these tasks when android application gone to background?
Will these tasks are processed even in the background? Will the complete UI thread be suspended in background? Or? All the tasks posted to UI thread are suspended?
Going to background does not change anything for the main thread. It's running until the application is killed. So your code scheduled on a handler will just run.
On a side note. The possible problem here is that while activity is in the background it can be killed by the system and you attempt to change UI of it will crash the app (there are a few similar scenarios), but it's not really related to the UI thread.
All in all, the UI thread is not suspended by the framework under any conditions. It just runs and processes everything you give it or waits until new tasks are given to it.
Here you can find the description of the main thread in the official docs.
This is a good SO thread about looper.
What happens to these tasks when android application gone to
background?
It will work as intended, No change in the behavior of UI Changes. Only thing is we are not able to see those changes.
Best Solution:
Update any view inside your handler when app is in background
eg: TextView and set some text in it, and get this TextView value once the application goes in the foreground.
Will these tasks are processed even in the background? Will the
complete UI thread be suspended in background? Or? All the tasks
posted to UI thread are suspended?
As I mentioned above this task will work as it is.
The application does not change UI thread when you move to the background, It will remain as it is.
What happens to UI thread when there are no tasks posted to it after
the activity is completely loaded? Will it be suspended, if there are
no tasks are in the Looper?
Putting it simply, there are Looper threads, for example, UI thread. Such thread has its own Looper, which runs a message loop for the thread. Once message queue is finished it will be finish itself.
UI thread will not be suspended at any cost by itself, Until and unless you write some code to change it :).
Nice to read:
Androids Handler.post, what happens exactly
What is the relationship between Looper, Handler and MessageQueue in Android?

i'm so confused about Threads

I read a lot about threads but don't understand yet :( let me explain to you what I have learned about threads. all we are working on such as codes any thing worked on UI thread or Main thread right? After that what happens if we call runOnUiThread? and my other question how do we know it's Time to use a new thread? I mean how do we understand we are working on another thread or replace or code in the new thread?
I know this is an unclear question but I don't understand as well. Please help me Thanks, john.
Let me try to answer. Actually Android has Main Thread (also called as UI Thread) and other thread.
Main Thread is basically for showing UI and other thread is for processing other big processes such as connecting to the server, etc.
runOnUiThread is called when you want to move from other thread to main thread. It is needed since only main thread can show/display result on UI. So when you have done some process on other thread, and you want to display the result on the apps, you need to show it on main thread by calling runOnUiThread.
We working on other thread only if it is a big or lengthy process like taking data from the server, load data, etc. And we move from other thread to main thread whenever we want to show some UI result.
Easiest way is to use AsyncTask<> class. You'll need to override three functions.
doInBackGround(...) : The codes that gets executed in background thread.
onPreExecute(..) : code that gets executed before background thread
completes executing like displaying progress bars, etc.
onPostExecute(...): Code that gets executed after background thread
has completed running. Perform task like updating UI in here
One general rule of thumb is: Don't use multithreading if you don't need to. Multithreading is always error-prone, and in many situations there's no benefit. Basically, you start a new thread whenever you execute a lengthy operation (i.e. some extensive computation like image processing) that would block the main thread for some time, so the application would become unresponsive.

Android -Activity - Thread Basics

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

How to know if this thread is a UI Thread

Is there any way on Android to know, if the thread running my code, is the UI Thread or not ? In swing there was SwingUtilities.isEventDispatchThread() to tell me if i am on the UI Thread, or not. Is there any function in the Android SDK that lets me know this ?
Answer borrowed from here: How to check if current thread is not main thread
Looper.myLooper() == Looper.getMainLooper()
Any Android app has only one UI thread, so you could somewhere in the Activity callback like onCreate() check and store its ID and later just compare that thread's ID to the stored one.
mMainThreadId = Thread.currentThread().getId();
Anyway, you can omit checking if you want to do something on the UI thread and have any reference to Activity by using
mActivity.runOnUiThread( new Runnable() {
#Override
public void run() {
...
}
});
which is guaranteed to run on current thread, if it's UI, or queued in UI thread.
Yes, there is a way.
Check the current thread object against main lopper's thread object. Main looper is always in the UI thread.
boolean isOnUiThread = Thread.currentThread() == Looper.getMainLooper().getThread();
Hum actually due to Android architecture, all Activities run in the main thread, ie the UI thread. So when you are coding an activity, everything that is in your Activity is in the UI thread.
That is why in Honeycomb an error have been added when you are making network calls in the main thread : it totally blocks the UI.
So by default you are in fact always working in the UI thread.
Another thing : unless you explicitely ask it to be in another thread, a Service will operate on the same thread as the activities of its application.
So, what to do ?
When you have to do heavy calculation in your activity; one solution is to use an AsyncTask (a class designed to allow you to easily use another thread). The code in onExecute() is run in another thread (but be cautious postExecute runs in your main thread). Another one is to manually start a new thread when AsyncTask is not really adapted.
If you create a service that does costly background tasks, make it run in another thread with the android:process=":my_process" attribute of the manifest. You will need to create an AIDL to communicate with this separated service, but it is not a complicated task.
Many objects, like for example the MediaPlayer, have Async variations of their methods. Try to to always use them.
Put a breakpoint where you want to check and, when it gets hit, check if you can interact with your UI (ie, if the UI is not frozen). If you can't interact with the UI then you are in the UI Thread, otherwise you are in a background thread.

Categories