I have searched the java API on Thread, Handler, HandlerThread, Looper , as well as SO, and cannot find an answer. Of course, I have also used Eclipse's debugger to step and inspect my 'msg'.
Situation: If you protect your data model from concurrency issues by allowing only one worker thread to have access to it, how would you then differentiate between a Runnable versus a Message in its handleMessage(Message msg) if you were enqueueing both Messages and Runnables in the same message queue?
Q. While my Runnables execute as planned after being posted via handler.postDelayed(myRunnable), I would like to inspect the contents of the Runnable while my worker thread is switching upon it so that I can update my data model appropriately.
I welcome all feedback and appreciate your time!
Below is the entire contents of 'msg' as shown from Eclipe's debugger. Is there even enough information here to switch on the Runnable?
msg Message (id=830030887816)
arg1 0
arg2 0
callback null
data Bundle (id=830030968104)
mAllowFds true
mClassLoader BootClassLoader (id=830023329296)
packages HashMap (id=830023329320)
parent null
mFdsKnown true
mHasFds false
mMap HashMap (id=830030980304)
mParcelledData null
flags 1
next null
obj null
replyTo null
target IncomingHandler (id=830031033176)
what 0
when 180369888
Below is my worker thread's handleMessage(). Specifically, I instantiated a HandlerThread as my worker thread and bound it's getLooper() to my worker thread Handler.
#Override
public void handleMessage(Message msg) {
// If this is a Runnable then I need to call my method.
// This next line is a hack to test for Runnable.
// I would like to know how to inspect this Runnable
if (0 == msg.arg2 && 0 == msg.arg1 && 0 == msg.what)
incrementStateMachineBecauseRunnableStarted();
// Determine which action to take
// http://stackoverflow.com/questions/5021246/conveniently-map-between-enum-and-int-string
switch (Cmd.values()[msg.what]) {
case RECEIVE_NEW_LIST_EMPLOYEES:
receiveNewListEmployees(msg);
break;
case UPDATE_ONE_EMPLOYEE_STATE:
updateOneEmployeeState(msg);
break;
default:
Log.e(this.getClass().getName(), "unexpected message.";
break;
}
This is how I enqueue my Runnable (I run this code on my worker thread, so it is sending a message to itself, to be processed later in handleMessage(Message msg)):
// Create a new Runnable for this employee
PostUpdate update = new PostUpdate(employee);
// Post this Runnable with a sort delay
postDelayed(update, WAIT_BEFORE_PUSH_MS);
... and this is how I enqueue my Messages (from another thread):
Message msg = mHandler.obtainMessage();
msg.what = Cmd.RECEIVE_NEW_LIST_EMPLOYEES.ordinal();
msg.arg1 = 77; // deliberately inserting debug value
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(Cmd.RECEIVE_NEW_LIST_EMPLOYEES.toString(), mEmployees);
msg.setData(bundle);
mHandler.sendMessage(msg);
Finally, my Runnable:
private class PostUpdate implements Runnable {
private final Employee mEmployee;
public PostUpdate(Employee employee) {
mEmployee = employee;
}
#Override
public void run() {
// Post update through network to MySql server
mDao.setState(mEmployee);
}
}
My conclusion from using the debugger and inspecting the elements is that you cannot determine in handleMessage() whether a message or a runnable is being processed.
I found empirically (through elimination) that all my Runnables had a msg.what == 0 when I set all my messages to have msg.what to be something other than 0. Use with care!
Related
I have a UI created in an activity which creates a handler for receiving messages.
I then launch a second thread for network communication. This second thread sends messages back to the UI thread via the UI threads handler.
All works OK as long as I send integer values.
However, if I set the objvalue to an object such as a string, when it arrives in the handler it has been set back to null.
The handler is declared like this :
private static class MsgHandler extends Handler
{
private CommsActivity m_parent;
public MsgHandler(CommsActivity parent)
{
m_parent = parent;
}
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case R.integer.msg_progress :
m_parent.ShowProgress(msg.arg1);
break;
case R.integer.msg_error :
m_parent.ShowError(msg.arg1, (String)msg.obj);
break;
}
}
}
When I need to send a message from the second thread, I call it in this manner :
msg = m_hMsgHandler.obtainMessage();
msg.what = m_iNormalMsgId;
msg.arg1 = R.integer.activation_lockout;
msg.obj = new String(strResponse);
msg.sendToTarget();
The MsgHandlerinstance is passed into the thread runnable as a parameter and stored for later use.
I have also tried using a Bundle instance, but this also is set to NULL.
Note that I am working with Android 4.4.
What do I need to do to overcome this limitation ?
try to send message using handler.
hope it helps
msg = m_hMsgHandler.obtainMessage();
msg.what = m_iNormalMsgId;
msg.arg1 = R.integer.activation_lockout;
msg.obj = new String(strResponse);
m_hMsgHandler.sendMessage(msg);
and check, that you process exactly this message (I see in yuor samples set msg.what = m_iNormalMsgId but in switch process case R.integer.msg_progress like msg.arg1 = R.integer.activation_lockout;)
This is how I'd try it:
m_hMsgHandler.sendMessage(
m_hMsgHandler.obtainMessage(
m_iNormalMsgId,
R.integer.activation_lockout,
0,
new String(strResponse)
);
handler is passed as this:
public void getUserYouTubeFeed() {
new Thread(new GetYouTubeUserVideosTask(responseHandler, username, i)).start();
}
Handler responseHandler = new Handler() {
public void handleMessage(Message msg) {
populateListWithVideos(msg);
}
};
and in the run method of thread
public class GetYouTubeUserVideosTask implements Runnable {
// A handler that will be notified when the task is finished
private final Handler replyTo;
public GetYouTubeUserVideosTask(Handler replyTo, String username, int frag) {
this.replyTo = replyTo;
}
#Override
public void run() {
// some code here
Library lib = new Library(username, videos);
// Pack the Library into the bundle to send back to the Activity
Bundle data = new Bundle();
data.putSerializable(LIBRARY, lib);
// Send the Bundle of data (our Library) back to the handler (our Activity)
//Message msg = Message.obtain();
Message msg = new Message();
msg.setData(data);
// getting null pointer exception here
replyTo.sendMessage(msg);
}
}
had this same issue. I wanted to create a client thread class in a separate .java file. In order to work, however, it would need to know the handler of the main UI thread. Unfortunately, since Java does not support pointers, passing the handler from the UI to your custom class and assigning it:
public GetYouTubeUserVideosTask(Handler replyTo, String username, int frag) {
this.replyTo = replyTo;
}
simply creates a copy of the handler and associates it with your thread (not a link to the main UI handler).
Messages sent to a thread (or main UI) require a Looper which dispatches the messages from the message queue, which then can be processed by the message handler. The main UI has a message loop associated with it by default, accessed through Looper.getMainLooper() and, therefore, you can simply create a handler in your main UI which threads can post to. Threads, however, don't have a message loop by default, so when you try to call:
replyTo.sendMessage(msg); // NullPointerException
you are actually trying to send the message to your new thread's handler which doesn't have a message loop associated with it causing the exception.
You can look at the Looper documentation to see how to create a message loop for you thread, but remember: the looper and the handler in your thread ONLY handle messages TO your thread (this is how you can communicate between threads).
The question is, where I tell my Thread to use mHandler for the Looper?
Thank you.
I am using the below code:
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();
}
}
The question is, where I tell my Thread to use mHandler for the
Looper?
You don't need to tell it explicitly, because the system (framework) does it for you. When you instantiate the Handler, it will automatically obtain access to the message queue of your current Thread. Quoting your comment:
How the system know to send the message to the mHandler Handler?
I'll detail it below.
This is the constructor of android.os.Handler in Android:
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
As you can see, first it obtains the Looper of your current Thread. The source code of Looper.myLooper() is as follows:
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
It obtains it from the thread local storage. Later, when you send a Message with this Handler, the Handler actually sets itself as the recipient of the Message: this is how the Looper will know where to dispatch the Message when it arrives. In details:
When you call mHandler.sendMessage(), eventually this code runs (among many other code lines):
MessageQueue queue = mQueue;
boolean sent = false;
if (queue != null) {
msg.target = this; // msg is your Message instance
sent = queue.enqueueMessage(msg, uptimeMillis);
}
As you can see, it sets the Handler instance as the target of the Message. So, later, when the Message is dispatched, it will contain the Handler as its target. This is how the Looper will know which Handler it should dispatch it to. In details, when you call Looper.loop(), the following happens for each of your Message instances in the queue:
msg.target.dispatchMessage(msg);
The dispatchMessage() code is the following:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Notice the last handleMessage(msg) call -- this is exactly your handleMessage(msg) override!
To have a better understanding, create a normal Thread and try creating a Handler in the run() method of that thread. You'll get a RuntimeException saying:
Can't create handler inside thread that has not called
Looper.prepare()
Now calling Looper.prepare() in the run() method before creating a Handler would create a new Looper object associated with the calling thread. The source of your confusion is that Looper.prepare() does not take a Thread as argument. It need not, since it's a static method, which internally gets the ThreadLocal of the currently running thread. There can be at most one Looper associated with any Thread.
Now, calling new Handler() would associate the new Handler object with the Looper of the current Thread by internally calling Looper.myLooper(). You can create more than one Handler each with its own Callback in the same Thread. All Handlers would get their messages from the message queue of the same Looper.
You don't tell anything. From the 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.
The handler is automatically bound to the thread's message queue. You only implement the callback, and the system will take care of everything, ie dispatching and processing the messages. Actually I agree that, using two static methods like Looper.prepare() and Looper.loop() and automatically infer things, makes the pattern feels like black magic :)
I want to write a module that connects to a remote Service.
The module can be used by developers in their apps to connect to a specific (bluetooth-)hardware. It should then connect to a single remoteservice that can be updated seperately in the market.
Because the Remote Service is only allowed to have a single thread for all the apps using it at the same time (Only one connection over bluetooth), I have chosen the messenger approach over AIDL.
My problem is now that I wanted to provide a synchronous method in my public API but the service returns in an handler - and as far as I have understood, the handler will allways wait for the current task to finish... So is there any way to get the answer in a differen thread?
the code of the synchronous method as I would like it to be:
responseDataSync = new Sync<ResponseData>();
// Send message
Message msg = Message.obtain(null, Constants.DATA, 1, 0);
send(msg);
try {
ResponseData responseData = responseDataSync.get();
// with responseDataSync using a countdown latch to synchronize...
// but it never fires thanks to the handler.
//etc...
Thanks in advance. I hope my question was somewhat understandable... ;)
/EDIT:
I want some method that returns data from the server. like
public ResponseData returnResponse(Data dataToSend)
but I can't wait for the service's return because then I am stuck in the thread what blocks the handler from returning...
A Handler is associated with a single message queue. If you send a Message from any Thread it will get enqueued there.
The Thread that receives all the Messages will get the appropriate message off the queue and handle it - one by one.
Meaning for you that if you have a Handler and you run all Messages through you handler you don't need synchronization since everything is handled in a single thread.
Edit: to create a Handler that handles messages in a background thread:
HandlerThread ht = new HandlerThread("threadName");
ht.start();
Looper looper = ht.getLooper();
Handler.Callback callback = new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// handled messages are handled in background thread
return true;
}
};
Handler handler = new Handler(looper, callback);
handler.sendEmptyMessage(1337);
Edit2: wait on Messages might work like this
// available for all threads somehow
final Object waitOnMe = new Object();
HandlerThread ht = new HandlerThread("threadName");
ht.start();
Looper looper = ht.getLooper();
Handler.Callback callback = new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// handled messages are handled in background thread
// then notify about finished message.
synchronized (waitOnMe) {
waitOnMe.notifyAll();
}
return true;
}
};
Handler handler = new Handler(looper, callback);
// in a different Thread:
synchronized (waitOnMe) {
handler.sendEmptyMessage(1337);
try {
waitOnMe.wait();
} catch (InterruptedException e) {
// we should have gotten our answer now.
}
}
I'm wondering how Handlers are processed in Android/DalvikVM. I'm writing an application for Android, and in one class I have a Handler method which receives messages from another class. Will the Handler method act as a Thread and be asynchronous to the run() method in the same class, or will it wait until a line of code in the run() method is finished (sort of atomic operation)? Or something else?
I'm wondering, because I want to add messages to a queue in the Handler method, and process and remove them in the run() method (producer-consumer).
My code structure:
public class Parser implements Runnable {
public void run() {
while(true) {
// Remove a byte from the ring buffer and parse it
byte b = Ringbuffer_read();
// Parse
try {
Thread.sleep(40);
} catch (InterruptedException e) {}
}
}
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
// Store all the received bytes in the ring buffer
for (int i = 0; i < msg.arg1; i++) {
Ringbuffer_store(((byte[]) msg.obj)[i]);
}
break;
}
}
};
}
When will the code in the handler run? Does it interrupt the code in the run() method at any point? Do I have to have some synchronization or semaphores or something around the code in the run() and handler method so that I don't corrupt my buffer?
An Android Handler associates itself with whatever thread it is created in (assuming that thread has a looper already). By default in Android callbacks run on a thread named "main" which is also called the ui thread. Regardless of what thread the post method is called from the handleMessage method will be called from the thread that the Handler was created in (usually the "main" thread). Because the handleMessage method is always called in the same thread, only one message will be processed at a time.
If your plan is to have only a single consumer then Handler is a good choice. You will not need to remove messages from your consumer (the Handler), instead they will simply arrive in handleMessage for processing. If you want to do processing on the "main" thread then you just make a new Handler, if you want to do processing in the background to avoid ANRs you will likely want to use HandlerThread. Here's an example of a Handler running on it's own background thread:
HandlerThread handlerThread = new HandlerThread("Consumer");
handlerThread.start();
Handler consumer = new Handler(handlerThread.getLooper()) {
public void handleMessage (Message msg) {
}
};
Notice that in the description above class does not come into play at all because classes are how code is structured which is unrelated to what thread the code is executed on.