Can anyone tell me if there's any difference between using runOnUiThread() versus Looper.getMainLooper().post() to execute a task on the UI thread in Android??
The only thing I can determine is that since runOnUiThread is a non-static Activity method, Looper.getMainLooper().post() is more convenient when you need to code something in a class that can't see the Activity (such as an interface).
I'm not looking for a discussion on WHETHER something should be executed on the UI thread, I get that some things can't and a great many things shouldn't, however, some things (like starting up an AsyncTask) MUST be executed from the UI thread.
The following behaves the same when called from background threads:
using Looper.getMainLooper()
Runnable task = getTask();
new Handler(Looper.getMainLooper()).post(task);
using Activity#runOnUiThread()
Runnable task = getTask();
runOnUiThread(task);
The only difference is when you do that from the UI thread since
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
will check if the current Thread is already the UI thread and then execute it directly. Posting it as a message will delay the execution until you return from the current UI-thread method.
There is also a third way to execute a Runnable on the UI thread which would be View#post(Runnable) - this one will always post the message even when called from the UI thread. That is useful since that will ensure that the View has been properly constructed and has a layout before the code is executed.
Related
I have some kotlin code like the following in an android app:
Thread(Runnable {
while (true) {
Thread.sleep(100)
... do useful work ...
if (checkCurrentCondition()) {
... do final useful work ...
return
}
}
}).start()
Here is my question: Is there some way (a callback function or some other mechanism) by which I can know in the main thread, that the background thread above has finished its job?
You may use AsyncTask or ThreadPoolExecutor. AsyncTask has the onPostExecute() method using which you can get the execution result right into UI Thread and do your job after. Also there is Looper/Handler usages for ThreadPoolExecutor to communicate between UI/Worker threads.
For detailed information's look here
If this is in an Activity, you could call runOnUiThread { doWhatever() } from the Thread - it'll hold a reference to the Activity, so don't do this in a long-running thread.
If you create a Handler with Handler(Looper.getMainLooper()) then you can post Runnables to it - basically the same as runOnUiThread except you're not holding onto an Activity, and you can do things like delay and cancel those posted messages.
If you already have some looping activity going on (so you can basically check if the thread's completed) then you could do anything from having a boolean done flag that the thread sets (make it #Volatile so the main thread sees the change) to all the stuff in java.util.concurrent like Futures and the like. Really depends on what you're doing.
Posting a Runnable to the main thread looper is the easiest general way to make a thing happen. But again, if that thread is creating any data in memory that the main thread needs to see, as always you need to handle synchronization, which is its own topic!
This question already has answers here:
How do we use runOnUiThread in Android?
(13 answers)
Closed 4 years ago.
In following code
The way we are using runOnUiThread
shouldn't this create issue with the existing UI Thread
hence creating an issue with the application , hence shouldnt be used
Thread thread = new Thread(new Runnable(){
#Override
public void run(){
//what is meant by the inside code of this run(), how is this updating the UI
runOnUiThread(new Runnable(){
#Override
public void run(){
}
})
}
})
In android,for long running task you should use separate thread such as AsyncTask() or service.Suppose you want to update your UI like you want to show any Toast to user then you should write runOnUiThread(),because only UI thread will allow to touch UI components.
getActivity().runOnUiThread(new Runnable()
{
#Override
public void run() {
Toast.makeText(getContext(), "API calling done!!", Toast.LENGTH_LONG).show();
}
});
There are two types of thread in Android.
1 is UI or Main thread on which your UI elements (layouts) are rendered.
2 is Worker Thread in which long task should be executed (like AsyncTask & Networking).
If you write some task in new Thread, that mean that task will be executed in worker thread.
Now you will use runOnUiThread or new Handler(Looper.getMainLooper()) because you can not touch UI elements in worker thread.
So basically when you are updating UI like setText(), or Toast or any UI operations, you will have to UI thread and you should use worker thread when you are doing some long executions.
Edit
Generally we don't have to manage threading in Android. Because all libraries we use are smart. Although in some cases we have to manage threading as well.
Example
Assume you are calling an web-service(api) in a new Thread, now when response comes you want show a Toast. If you just write Toast.show... directly in response inside worker Thread you will get exception.
Only the original thread that created a view hierarchy can touch its views.
Now to overcome this issue you have to use runOnUiThread, so that you can show Toast.
Whenever we have some Long running tasks we switch to some worker threads and avoid Main Thread and allow a smoother user experience and avoid ANR.
But, when the time comes to update the UI we must “return” to the
Main Thread, as only Main Thread is allowed to touch and update the application
UI.
we can achieve this by making a call to the Activity’s runOnUiThread() method:
Basically what runOnUiThread() will do is - Runs the specified action
on the UI thread. It will check the current thread and if it finds its
the MainThread it will execute that task immediately , otherwise first
it will switch you to app MainThread and then it will execute the
given task.
When a new Thread is created and executed, it does the task in the background thread. But the method runOnUiThread() is used for running the code on the main UI thread.
In your code, runOnUiThread() method is called and hence you are able to update the UI thread from the other thread.
when thread is running in the method runOnUiThread () will update the UI Components (textview .. etc..)
by calling runOnUiThread, you can update the status too
shouldn't this create issue with the existing UI Thread
Not at all. You said "existing UI Thread". There is only one UI thread. The runOnUiThread() will only add the runnable to a queue of tasks which the UI thread executed one by one. You can check the doc.
No worries! This is one of the standard way for updating UI components from a separate thread or even on UI thread itself on Android platform.
Also, runOnUiThread is an method of Activity class, it runs the specified action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread.
Another standard way is using Handler and Message as officially documented by Android Developer here https://developer.android.com/training/multiple-threads/communicate-ui
I've got this piece of code:
public void updateOptionLists() {
Log.d("UI", "Called update");
if (updating){
return;
}
updating = true;
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Log.d("UI","Updating");
}
});
Log.d("UI", "Posted update");
}
What I'd expect from logcat would be something like this:
Called update
Posted update
Updating
As far as I know runOnUi should be asynchronous, right? And considering that the functions called alter the views, which takes a while, this should be running asynchronous. Right?
So I look at my logcat:
Called update
Updating
Posted update
Why does this happen? And how do I make sure this runs asynchronous?
runOnUiThread will execute your code on the main thread, which (in this example) also appears to be where it's called from. This explains the ordering of the log statements you see - all code is executing on a single thread, so is synchronous per the documentation (my emphasis):
Runs the specified action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread.
runOnUiThread is typically used to execute code on the main thread from a different (i.e. background thread). The use of this separate background thread is what will make a task asynchronous. Calling back to the UI thread at the end of that task is required if you want to modify UI with the results of your background thread calculations.
Android provides several mechanisms for doing work on a background thread and then posting back to the main thread (not all use runOnUiThread explicitly for the latter operation). Good things to read up on include Thread, Handler, AsyncTask, Service, etc.
As far as I know runOnUi should be asynchronous, right?
runOnUiThread, as the name states, runs on UI thread, which is a main thread of an application. It runs synchronously with other code running within that thread and asynchronously with code in other threads.
The word 'asynchronous' has no meaning without a context: some code can run asynchronously with other parts of the code, which means these parts of the code run in different threads. Saying that something 'should be asynchronous' makes no sense without this kind of context.
is updateOptionLists running on the UI Thread?
If this is the case, i would expect this behavior to be ok.
In a normal case you use runOnUiThread from a background thread to come again to the Ui Thread..
Because you call upadetOptionLists() on ui prosess, upadetOptionLists() and runUiThread() both run in the same thread.
To separte theam you need run content in other new thread as following
public void updateOptionLists() {
new Thread(new Runnable() {
#Override
public void run() {
Log.d("UI", "Called update");
if (updating){
return;
}
updating = true;
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Log.d("UI","Updating");
}
});
Log.d("UI", "Posted update");
}
}).start();
}
For accessing the view, you must be in the UI Thread (the main one). So, runOnUiThread will be executed on it.
You must do the long work in an other thread and only call runOnUiThread for little thing like changing a color or a text but not to calculating it.
From the documentation:
Runs the specified action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread.
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)
Multi Threaded Programming: Theory vs Actual
Puppy Photos Explain is the Best pic.twitter.com/adFy17MTTI— Cian Ó Maidín (#Cianomaidin) 6. april 2015
But joke aside.
If you want to test how the threads work in correlation, try:
runOnUiThread(
new Runnable() {
#Override
public void run() {
updating = false;
updateOptionList();
scrollToLastTapped();
Thread.sleep(100);
Log.d("UI","Updating");
}
});
I will come out straight that this is a assignment question .So I am not looking for a answer but a better answer .
We have a Async Task which takes in three parameters . The progress parameter(i.e 2nd parameter is) is a Runnable .
#Override
public void onProgressUpdate(Runnable ...runnableCommands) {
// TODO -- you fill in here with the appropriate call to
// the runnableCommands that will cause the progress
// update to be displayed in the UI thread.
}
I am able to make calls to this method using publishProgress() in doInBackGround() method.
The challenge is to have this runnable attached to UI Thread. I know that onProgressUpdate() has access to UI thread and we can create a handler to add to message queue . But apparently it is excessive.
Can some guide me to a better way to do this than create a handler
If you have a reference an Activity, an easy way is using the runOnUiThread(Runnable runnable) method. Looking at the source code, it's really easy to see why:
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
If you have a reference only to a View, you can use the post(Runnable runnable) method.
The JavaDoc for both states the Runnable will be executed on the main thread.
According to the documentation
onProgressUpdate
This method can be invoked from doInBackground(Params...) to publish updates on the UI thread while the background computation is still running.
You can find a link here AsyncTask
Basically this method already runs on the UI thread. So you dont need any further code (via handelrs or runOnUiThread()).
In your case, you can just directly call run of that Runnable.
I have a bunch of AsyncTasks and their callbacks (listener interfaces) that I dont want to have anything to do with the UI thread.
Reading the answer here: Android : can AsyncTask return in another thread than UI thread?
I am left with the impressin that I can only start AsyncTasks from the UI Thread which means the callbacks that I invoke from their onPostExecute methods will also be in the main thread.
How do I move all this logic away from the UI thread?
First, based on some issues I've had before when trying to run AsyncTasks in an IntentService, I think your assumption that you cannot run an AsyncTask from a non-UI thread is false.
The problem I've found with starting AsyncTasks off the UI thread is not that they don't run or that they cause crashes, but that onPostExecute() doesn't automatically run on the main UI thread after the other stuff finishes. I wouldn't recommend doing it, but you probably could if you wanted to.
But the whole reason AsyncTasks exist are basically to have an easy way to run some code off the UI thread and then be able to alter UI stuff after it's finished. So if you don't want to do anything at all with the UI thread, you shouldn't need to use an AsyncTask at all. If you don't need to run any code on the UI thread, you can just use something like:
new Thread(new Runnable() {
public void run() {
//Do your stuff
}
}).start();