Android handler association - android

Android doc says: "Each Handler instance is associated with a single thread.."
So, if I define the following handler inside onCreate() method:
myHandler= new Handler();
then myHandler will be associated with the main (UI) thread?
I would like to see an example where a handler is "associated" with a worker thread. If you have any, I would appreciate.
Thanks.

There are two questions here.
The answer to the first is "yes". If that line of code is in onCreate, then myHandler is associated with the UI thread
A Handler is cannot be associated with just any thread. It must be associated with a Looper. The very first paragraph of the documentation of the Looper gives an example.

This much is true: If you use the default constructor for Handler, then your Handler object will be associated with the current thread - whatever it is.
However, you will note that the Handler class has several other constructors. If you provide the Looper argument to the Handler constructor, then your handler will be associated with the thread that is associated with the Looper. (Note that Looper detects and holds onto the thread that it is constructed in.)
You can create a Thread with a Looper by instantiating a Looper in the thread's run() method. But Android has already done this for you in the HandlerThread class: HandlerThread class is a subclass of Thread and has a Looper - perhaps a better name for HandlerThread would have been LooperThread. In any case, HandlerThread class also has a method called getLooper(). So, you first create an instance of HandlerThread, and then use its getLooper() as an argument to your Handler constructor:
HandlerThread myLooperThread=new HandlerThread("LooperThread");
myLooperThread.start();
Handler myLooperHandler=new Handler (myLooperThread.getLooper(),
new MyLooperHandlerCallback());
myLooperHandler.sendEmptyMessage(50);
The above snippet can be executed in your UI thread, but will still associate myLooperHandler with the HandlerThread's thread. You can verify this, by logging thread id, as in:
//runs in HandlerThread's thread
public class MyHandlerCallback implements Callback {
#Override
public boolean handleMessage(Message msg) {
Log.i("CALLBACK", "Thread ID:"+android.os.Process.myTid());
Log.i("CALLBACK", "msg.what:"+msg.what);
return true;
}
}
Note that it is best to instantiate threads in retained worker fragments, so that they are accessible across Activity boundaries.

Related

Does declaring multiple Handler instance create multiple queue?

I have a class with multiple functions, each function were containing a separate handler to execute a runnable. Recently I realized that we must remove all the callbacks on the onDestroy method to avoid memory leaks, so for that, I declared a class-level handler and used the same handler to post runnable in all the functions.
Now my confusion is, what happens if we use the same instance of Handler for multiple runnable compared to a separate handler instance for each runnable?
No matter how many handlers you have, all those handler will pos their messages to the same queue which is main thread queue by default, unless you attach the handler to different looper objects excplicitly. To illustrate in code:
// This handler will be attached to the main thread's looper,
// hence to its queue implicitly but however this constructor
// is deprecated and is not recommended.
Handler handlerMain = new Handler();
// This handler will be attached to the main thread's looper
// object explicitly and this is the recommended way by Google.
Handler handlerMain = new Handler(Looper.getMainLooper());
// Another handler will be attached to the main thread's looper object.
Handler handlerMain2 = new Handler(Looper.getMainLooper());
// This is a custom handler thread whis has a looper object same as the apllication's main (ui) thread. But this one will be a background thread.
HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();
// Now this handler will post messages to the mHandlerThread's queue.
// Hence you cannot access directly to the UI elements from this thread,
// you must post the ui touching codes to the main thread's queue.
Handler handlerCustom = new Handler(mHandlerThread.getLooper());
You can attach many handlers to a looper, the handlers are not the problem. The problem is the code that they post. You can post a delayed code that will be executed in a future time, and that code touches some UI elements of a fragment or access context of a fragment. The problem comes when the fragment's view and context is destroyed before the posted code has been executed.

HandlerThread and Handler: how to use AudioRecord.setRecordPositionUpdateListener?

I'm confused by Handler and HandlerThread classes usage. The reason I'm trying to use them is I want to utilize AudioRecord class and its setRecordPositionUpdateListener method (reference). The methos description says:
Use this method to receive AudioRecord events in the Handler associated with another thread than the one in which you created the AudioTrack instance.
And that's exactly what I want - to setup the AudioRecord in the main thread, but receive data in a working thread. I figure I need a HandlerThread so I've created and started one. I've also defined a callback method that implements AudioRecord.OnRecordPositionUpdateListener interface. I want this callback to be called from the worker HandlerThread. What I don't understand now is how to create the Handler to pass to setRecordPositionUpdateListener.
To associate Handler with a certain thread, you should create it by passing corresponding Looper in its constructor. So, if you already have a HandlerThread it can be done in the following way:
Looper looper = myHandlerThread.getLooper();
Handler handler = new Handler(looper);
And that's it, just use this handler in setRecordPositionUpdateListener method and callback will be executed at the worker thread. If you need more explanation on Handler, Looper and HandlerThread, you can take a look here.

Handler constructor stops a thread in Android

There's something weird happening. I can't show all the code, but situation is like this;
Runnable program = new Runnable() {
#Override
public void run() {
//This code is running
new Handler();
//This code not running
}};
new Thread(program).start();
Log shows nothing. Main thread is working good.
You should always declare Handler in UI thread.You need to provide the Handler with a Looper from some thread.E.g. from main UI thread:
Handler mHandler = new Handler(Looper.getMainLooper());
Handler always runs in the Looper thread context. When you create another thread its context is different from the Looper. Right solution is to declare Handlers always in onCreate(), onStart() and onResume().
Creating a Handler needs a Looper polling on that thread first. By the way, there's usually no need to create a Handler inside non UI threads. Create a Handler outside the runnable. An easier alternative is to use runOnUiThread() method.

Communication between worker threads

I am programming in Android environment, and I have in my project a Main Activity, in which there is an AsynkTask class, and separately a Thread object, realized extending Runnable interface. Now, AsynkTask and the Thread can be seen as two worker threads managed by the main thread, that is the Main Activity. How can I do if I want to make possible the communication between the two worker threads, not involving the main thread? How can I use handlers to realize this? I know how to use handlers between main and worker threads. I want to know how use them only between the worker threads, because in this case I can't pass in constructors handlers, because in this case I can not directly instantiate a thread, passing it as a parameter the handler created by the main thread. The main thread must create two worker threads, and they must communicate without the involvement of the main thread.
I hope I have been clear enough.
If you want to use a Handler with a worker thread you have to create a Looper on that Thread as explained in http://developer.android.com/reference/android/os/Looper.html.
Like this:
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();
}
}
And then you can send messages to mHandler from any other Thread.

Create Handler in a class without get error "Looper not prepared"?

In my game, there is an game object class that need to use Handler to post a delay Runnable. However, everything I try to create an Handler in the object class, I receive error message:
Can't create handler inside thread
that has not called Looper.prepare()
I've Googled some solution, but all of them use another solution, not Handler. Is there any solution to use Handler in a normal class? Or any solution to run a Runnable after a determined delay?
I can't use sleep, because it paused all my game!
Thank you.
You are probably creating the Handler from a non-UI thread. Either (1) you attach your handler explicitly to the UI thread by passing the UI thread's looper to Handlers constructor, which means that messages posted to the Handler are also executed on the UI thread, or (2) you create a new Looper for the non-UI-thread: see here.
edit regarding (1): you would have to somehow pass the UI thread's looper to the "game object", for example when it is created. You can get a reference to UI's looper by calling getMainLooper() on a context (e.g. from an activity).
An alternative would be to create the handler in the activity and just pass the handler to your game object.

Categories

Resources