Each Android thread is associated with Looper(Message Queue)? - java

I am trying to understand threads,handlers,loopers. I have watched the video where guy said following Each Android thread is associated with Looper(Message Queue). So that means that when I am creating Thread class instance it is implictly creates it own looper which is connected to this thread ? Or this is wrong ? Handler is connected to the thread where it was created, if there is no looper in each thread where handler will post messages ?
And another question is about HandlerThread . What is the purpose and what are pros and cons of using this class.
I hope for your help.Thanks everyone in advance.
EDIT
I wonder if Looper is associated with thread after just calling for example
Thread myThread = new Thread();
Or you should specify explictly lopper for thread calling Looper.prepare(); in your thread in turn implictly creating new instance of looper associated with the thread where method has been called. As I can see in sources of Looper class it calls ThreadLocal.get in prepare where is it gets current thread. So conclusion is that there is no looper associated with simple thread by default ? Am I right ?
And I have also noticed that all constructors of the Handler call Handler(Callback callback, boolean async). Looper.myLooper(); method is called.
So as I have understood it means following.
Thread myThread = new Thread(new Runnable() {
public void run() {
//some stuff here
}
});
myThread.start();
No Looper here is associated with thread.
Next example.
Thread myThread = new Thread(new Runnable() {
public void run() {
Handler myHandler = new Handler();
}
});
myThread.start();
Here Handler will be associated with looper implictly while creating new instance of Handler.
Next example.
Thread myThread = new Thread(new Runnable() {
public void run() {
Looper.prepare();
}
});
myThread.start();
In this example loooper will be created to explictly by calling prepare method.
I am right ? Please comment.
EDIT 2
The second example will cause
java.lang.RuntimeException: Can't create handler inside thread that
has not called Looper.prepare() such exception so conclusion is that
only thread that has called Looper.prepare()
; will have it's own Looper otherwise it will cause exception while creating handler inside such thread.

A thread becomes associated with a message queue by calling Looper.prepare(). Any Handler subsequently created in that thread will be associated with the same message queue. The thread begins processing its message queue by calling Looper.loop(). A looper thread typically won't do anything except process its own message queue.

From my understanding, Looper and Handler are just helper classes for easily handle generate and handle message in threads. But thread can do anything besides handling message.

Related

Which thread does Runnable run on?

I want to update UI every 100ms. After searching in StackOverflow, I found a solution using Runnable and Handler like this
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
//update UI here
handler.postDelayed(this, 100);
}
};
runnable.run();
It works! But I have some questions:
Which thread does this Runnable run on? MainThread or another thread? Here is the docs about postDelay
Handler is attached MainThread, so is Runnable running on MainThread?
If Runnable is running on MainThread, why needs Handler? According to my knowledge, Handler is used to send messages between two threads
Which thread does this Runnable run on?
Runnable runnable = new Runnable() {
#Override
public void run() {
//update UI here
handler.postDelayed(this, 100);
}
};
runnable.run()
This Runnable runs on the current thread, i.e. the thread that invokes this code. It doesn't magically create, or constitute, another thread. Runnable.run() is only a method call.
The subsequent executions of this thread, by the Handler, in whatever thread the Handler runs in, do essentially nothing except reschedule themselves. It's hard to believe this is a solution to anything.
In your example, the Runnable runs on the UI Thread.
If you want your Handler and all its Runnable to run in a different Thread, you'll have to assign it a a new HandlerThread's Looper.
final HandlerThread handlerThread = new HandlerThread(MY_THREAD_ID);
handlerThread.start();
final Handler handler = new Handler(handlerThread.getLooper());
You can then pass the Runnable instance via postDelayed(Runnable, long).
Runnable r = new Runnable() {
#Override public void run() {
handler.postDelayed(this, 2000);
}
};
handler.postDelayed(r, 0);
Handler is attached MainThread, so is Runnable running on MainThread?
From Handler documentation:
Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
If you want to run your Runnable on different Thread, you can use HandlerThread .
Related post:
Why use HandlerThread in Android
If Runnable is running on MainThread, why needs Handler? According to my knowledge, Handler is used to send messages between two threads
There are two main uses for a Handler:
To schedule messages and runnables to be executed as some point in the future
To enqueue an action to be performed on a different thread than your own.
If you are using only MainThread,Handler is useful to send message at some point of time in future. If you are using different Threads, Handler is useful to communicate between the threads.

How to access main thread from worker thread in Java?

Read many overkilled, overcomplicated solution here in SO, for such an easy question, how to access main thread from a worker thread, to execute some code on it.
In iOS dispatch_get_main_queue() method returns main thread. How in Java?
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0UL), ^{
//do background thread stuff
dispatch_async(dispatch_get_main_queue(), ^{
//update UI
});
});
In Android you can't access the main thread (UI Thread) directly, but you can queue jobs on it, so you need to create a Handler and using that handler to post jobs (Runnable) on main thread.
Below is an example of how you can post on UI Thread using Handler
new android.os.Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//Doing job here
}
})
and also as #CommonsWare mentioned in the comments, there is another ways to access UI thread:
if you have instance of any View you can use View.post(Runnable)
if you have instance of Activity, you can use Activity.runOnUiThread(Runnable)
Btw accessing main thread in Android is totally different than Java Desktop Apps
Running your code on main thread from another:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your code here
}
});
Hope this helps

What is the best way to wait until a runnable on the main thread completes in Android?

I need to collect a username and password from a user inside WebViewClient#shouldInterceptRequest, so I must block the WebView IO thread until the user supplies a username and password on the main thread. What is the best way to wait until my runnable completes?
My current favorite way is (exceptions and timeouts omitted for brevity):
final CountDownLatch countDownLatch = new CountDownLatch(1);
new Handler(Looper.getMainLooper()).post(new Runnable() {
public void run() {
callSomethingWithAsyncCallback(new Runnable() {
public void run() {
countDownLatch.countDown();
}
});
}
});
countDownLatch.await();
Something that uses ExecutorServices seems better since I can simply use Future#get to block. However, there is no ExecutorService that runs on the main thread, and using one from Executors just to bounce it to the main thread seems wasteful. Thoughts?
Please use AsyncTask rather than using runnable.
The AsyncTask executes everything in doInBackground() inside of another thread, which does not have access to the GUI where your views are.
preExecute() and postExecute() offer you access to GUI before and after the heavy lifting occurs in this new thread, you can even pass the result of the long operation to postExecute() to then show any results of processing.

Can't create handler inside thread that has not called Looper.prepare() - Android Marmalade

I'm trying to add USB controller support to my Android game. I'm using Marmalade and I've created an extension based on the USB example code. Here it is:
public class GameControllerInput extends Activity
implements InputManager.InputDeviceListener
{
private static final String TAG = "GameControllerInput";
private InputManager mInputManager;
private SparseArray<InputDeviceState> mInputDeviceStates;
private static int numEvents = 0;
public int EDK_GameControllerInput_Init()
{
LoaderActivity.m_Activity.runOnUiThread(new Runnable()
{
public void run()
{
Log.i(TAG, "Running 1 =========================");
}
});
Log.i(TAG, "Init 2 =========================");
return 1;
When I call the init function I get this error:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I've read other threads with this error and they say the solution is to add the LoaderActivity.m_Activity.runOnUiThread(new Runnable() code. However, as you can see, adding this just gives me the same error.
I'm not experienced with Java and I'm at a loss on how to fix this. Any help would be greatly appreciated.
Cheers,
Steve
A Looper (a message queue processor) is tied to a single thread, each thread has at most one looper. A Handler needs to register itself with a Looper to work, so each time you invoke new Handler(), it tries to get the Looper for the current thread (the thread that's creating the Handler), which can be either present or not. The exception that you see is thrown because the thread that's creating the handler does not have a looper.
There is one two things that you can do to fix this:
Add a Looper to the current thread.
Make sure you're creating the Handler on a thread that already has a Looper.
In almost all cases, the handler is used to communicate from a background thread to the UI thread, I'm assuming that's the case here. That means option 2. Your runOnUiThread(Runnable) thing is close, but no cigar, because all it does is write to the log file.
You need to move the code that creates the new Handler() (not shown in your posted code sample) into the runOnUiThread block, or use some other way to get it to run on the UI thread. The typical way to do this is to create it in the onCreate(Bundle) method of your activity or fragment.
Keep in mind that, depending on your initialization order, this may mean it's initially null as seen by your background thread, so the background code will have to be able to deal with that.
Well it's better to have a callback method and mark it as main thread only by calling run_on_os_thread after the method declaration in s4e file.

JAVA: Possible to add a runnable thread into a queue?

I recently began working with Threads and I am trying to complete a Java implementation of the Looper class in Android. Basically I am making a Java class that puts threads into a queue that will then be executed by the Looper class. I have the code completed for the most part but have an issue with the enqueuing of tasks.
In the Looper class I have the queue declared and my enqueue method:
List<Runnable> queue;
public synchronized void enqueue(Runnable runnable) {
queue.add(runnable);
notify(); // signal a waiting thread
}
I then created another class called TaskManager to add Tasks into the queue. I receive the error when I call:
loop.enqueue(new Task());
Where Task() implements runnable and just adds two integers together in its run() method...this is just a test.
The error I receive is:
Exception in thread "Thread-0" java.lang.NullPointerException
at Looper.enqueue(Looper.java:20) (this is the queue.add(runnable))
at TaskMaker.run(TaskMaker.java:16) (this is the loop.enqueue(new Task())
I'm obviously doing something wrong and not implementing this right...how should I go about this? Is the way I am enqueuing the task right? Thanks for any help it is much appreciated!
Are you initializing the queue variable? like:
List<Runnable> queue = new ArrayList<Runnable>();

Categories

Resources