Just clarifying but in an Android activity on MAIN Thread if I call Looper.myLooper() vs Looper.getMainLooper() the return the same reference, right? they are the same thing? I know I would never have to call these usually as Android takes care of this but I'd like to know how they differ when being called from the main thread?
if from the main thread I call
Looper.myLooper().quit();
// or
Looper.getMainLooper().quit();
They both give the same runtime exception so I'm assuming they are the same reference:
Caused by: java.lang.RuntimeException: Main thread not allowed to quit.
can anyone confirm?
You have it described in the docs:
getMainLooper()
Returns the application's main looper, which lives in the main thread of the application.
myLooper()
Return the Looper object associated with the current thread. Returns null if the calling thread is not associated with a Looper.
As for whether getMainLooper() is of any use, I can assure you it really is. If you do some code on a background thread and want to execute code on the UI thread, e.g. update UI, use the following code:
new Handler(Looper.getMainLooper()).post(new Runnable() {
// execute code that must be run on the UI thread
});
Of course, there are other ways of achieving that.
Another use is if you want to check if the currently executed code is running on the UI thread, e.g. you want to throw/assert:
boolean isUiThread = Looper.getMainLooper().getThread() == Thread.currentThread();
or
boolean isUiThread = Looper.getMainLooper().isCurrentThread();
Looper.getMainLooper() is convenience API to get looper which is attached to the main thread of the activity.It is usefull when you want to excute some code on main thread from a background thread.
It is usually used as follows:
new Handler(Looper.getMainLooper()).post(task);
Looper.myLooper() is api to get looper attached to current thread
If you call these two methods in the main thread, they are the same object! You can find answers in the source code of ActivityThread.java, Looper.java and ThreadLocal.java.
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!
I have the following Kotlin code, executed from the UI thread of Android:
Runnable {
doSomeSuff() // Which thread will it run?
}.run()
On which thread will it run? The UI thread?
Your Runnable will be executed on the Thread it was created. In your case - UI thread. The question is - what do you want to achieve? There are bunch of built-in capabilities to perform background related work. I'll provide wider answer - if you explain your requirements.
From Android Documentation:
The Runnable interface should be implemented by any class whose
instances are intended to be executed by a thread. The class must
define a method of no arguments called run.
This interface is designed to provide a common protocol for objects
that wish to execute code while they are active. For example, Runnable
is implemented by class Thread. Being active simply means that a
thread has been started and has not yet been stopped.
Why it is different from Thread:
When an object implementing interface Runnable is used to create a
thread, starting the thread causes the object's run method to be
called in that separately executing thread.
I am a beginner in android application development.I am working with threads in android.I have read about a runOnUiThread which run code on main UI(if i am not wrong?i guess.).
My question is what is the difference between normal code on main UI and code inside runOnIUThread.
Example:1
class A
{
getDataFromServer(foo);//Code on mainUI
}
Example:2
getActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
getDataFromServer(foo);
}
});
What is difference in both example.Please help me.Your response will be a new learning for me.
Assuming that you meant simple code for UIThread code,
What is a thread ?
A thread defines a process running
First runOnUiThread ..
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.
What is UIThread
Main thread of execution for your application
Most of your application code will run here onCreate, onPause, onDestroy, onClick, etc.
So simply Anything that causes the UI to be updated or changed HAS to happen on the UI thread
When you explicitly spawn a new thread to do work in the background, this code is not run on the UIThread.Now what if you want to do something that changes the UI?
Then you are welcome to runOnUiThread
You have to use runOnUiThread() when you want to update your UI from a Non-UI Thread. For eg- If you want to update your UI from a background Thread. You can also use Handler for the same thing.
Normally your code is executed on your UI thread. For longer taking tasks (such as network requests, etc...) you will use a background tasks (Handler, AsyncTask, Thread, ...).
As your Views can only be touched from a UI thread, you use runOnUiThread() if you are executing code in a background thread and you need to update your views, from this background thread.
To explain 'why' Android has the 'runOnUiThread()' option, it is important to understand that java is only used to create the bytecode (dex) that Android uses. The code running on the phone is NOT java.
Additionally, Android threads 'can' have a thing called a 'looper'. This 'looper' is what handles 'tasks(technically runnables and messages)' in order via a queue. The 'main ui thread' has by default a looper already attached to it.
That means that your runnable you created was put onto the looper's queue of the main UI thread. (this is why the runnable is NOT instantaneously ran, but will be ran 'quickly'/'soon')
The reason you'd use a runnable to run code on the UI thread is because you are in some other 'background thread' that you created... and want to update the UI in some way. (Only the UI thread can interact with the UI)
As far as I know the UI thread is the main thread.
getMainLooper according to the documentation is the UI thread.
The Application context thread shouldn't be the UI thread as well?
Also, the Fragment's Looper thread shouldn't be the UI thread as well?
Why the following fails (both)?
if (getActivity().getApplicationContext().getMainLooper().getThread() == Looper.getMainLooper().getThread()) {
throw new Exception("Context is not the application's thread");
}
//Inside a Fragment
if (new Handler().getLooper().getThread() == Looper.getMainLooper().getThread()) {
throw new Exception("Handler is not for the main thread");
}
i do not understand your question but i think my answer makes it clear:
getActivity().getApplicationContext().getMainLooper().getThread() returns the thread associated to UI thread or equivalently main thread.
Looper.getMainLooper().getThread() also returns above thread. so they both actually one object so the if condition is true that means:
"Context thread IS the application's thread"
if you are on main thread then new Handler().getLooper().getThread() returns exactly above thread. and also Looper.getMainLooper().getThread() so the two refrences are actually point to one object so the condition is true and
The handler thread IS the main thread
you can easily check those if statements. :-)
Why the following fails (both)?
No, i think you get confused the exception meaning. you throw the exception if the condition is true and the condition is true. that is not the same meaning of android exception this is your custom one and it throws correctly because the condition is satisfied.
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.