Example communicating with HandlerThread - android

I want to set up a HandlerThread from the GUI thread. Then some time later, when a button is clicked on the GUI, it runs callHello(), which then send a message to a HelloLogger object residing on the non-GUI thread which asynchronously logs "Hello World". I have tried a number of things, some block indefinitely, some never receive the message, etc etc. The code below is more or less as close as I have got, please could someone modify it to work?
public class HandlerThreadExample {
private MyHandlerThread mMyHandlerThread;
private Looper mLooper;
private Handler mHandler;
public HandlerThreadExample(){
mMyHandlerThread = new MyHandlerThread();
mMyHandlerThread.start();
mLooper = mMyHandlerThread.getLooper();
}
public void callHello() {
mHandler.sendEmptyMessage(1);
}
private class MyHandlerThread extends HandlerThread {
private HelloLogger mHelloLogger;
private Handler mHandler;
public MyHandlerThread() {
super("The MyHandlerThread thread", HandlerThread.NORM_PRIORITY);
}
public void run (){
mHelloLogger = new HelloLogger();
mHandler = new Handler(getLooper()){
public void handleMessage(Message msg){
mHelloLogger.logHello();
}
};
super.run();
}
}
private class HelloLogger {
public HelloLogger (){
}
public void logHello(){
Log.d("HandlerThreadExample", "Hello World");
}
}
}
Best examples found:
HandlerThread Test
How to create a Looper thread, then send it a message immediately?
Async calls with Handler
HandlerThread vs Executor - When is one more appropriate over the other?
Best use of HandlerThread over other similar classes
Android HandlerThread
HandlerThread examples
Android: Passing data between main and worker threads
Java Synchronised
Sending messages between threads using activity thread queue and Handler class
Intro to Loopers and Handlers
developer.android: Specifying the Code to Run on a Thread
At least now I can close the damned tabs
Solution courtesy of help from pskink
public class HandlerThreadExample2 {
private static int MSG_START_HELLO = 0;
private static int MSG_HELLO_COMPLETE = 1;
private HandlerThread ht;
private Handler mHtHandler;
private Handler mUiHandler;
private boolean helloReady = false;
public HandlerThreadExample2(){
ht = new HandlerThread("The new thread");
ht.start();
Log.d(App.TAG, "UI: handler thread started");
mUiHandler = new Handler(){
public void handleMessage(Message msg){
if (msg.what == MSG_HELLO_COMPLETE){
Log.d(App.TAG, "UI Thread: received notification of sleep completed ");
helloReady = true; }
}
};
mHtHandler = new Handler(ht.getLooper()){
public void handleMessage (Message msg){
if (msg.what == MSG_START_HELLO){
Log.d(App.TAG, "handleMessage " + msg.what + " in " + Thread.currentThread() + " now sleeping");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(App.TAG, "Woke up, notifying UI thread...");
mUiHandler.sendEmptyMessage(MSG_HELLO_COMPLETE);
}
}
};
}
public void sendLongHello(){
if (helloReady){
Log.d(App.TAG, "sending hello " + Thread.currentThread());
mHtHandler.sendEmptyMessage(MSG_START_HELLO);
helloReady = false;
} else {
Log.e(App.TAG, "Cannot do hello yet - not ready");
}
}
}

This is a working example:
HandlerThread ht = new HandlerThread("MySuperAwesomeHandlerThread");
ht.start();
Handler h = new Handler(ht.getLooper()) {
public void handleMessage(Message msg) {
Log.d(TAG, "handleMessage " + msg.what + " in " + Thread.currentThread());
};
};
for (int i = 0; i < 5; i++) {
Log.d(TAG, "sending " + i + " in " + Thread.currentThread());
h.sendEmptyMessageDelayed(i, 3000 + i * 1000);
}
UPDATE:
Make two class fields:
Handler mHtHandler;
Handler mUiHandler;
and try this:
HandlerThread ht = new HandlerThread("MySuperAwsomeHandlerThread");
ht.start();
Callback callback = new Callback() {
#Override
public boolean handleMessage(Message msg) {
if (msg.what == 0) {
Log.d(TAG, "got a meaasage in " + Thread.currentThread() + ", now sleeping... ");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "woke up, notifying ui thread...");
mUiHandler.sendEmptyMessage(1);
} else
if (msg.what == 1) {
Log.d(TAG, "got a notification in " + Thread.currentThread());
}
return false;
}
};
mHtHandler = new Handler(ht.getLooper(), callback);
mUiHandler = new Handler(callback);
mHtHandler.sendEmptyMessageDelayed(0, 3000);
You can of course get rid of Callback interface and create two Handlers with overridden handleMessage method...

The issue you are seeing is because your outer class is using a private mHandler field and so does your HandlerThread. The outer class' field is not initialized. You don't need the inner mHandler. The outer class can crate a handler from the looper you grab right after calling start().

Related

Android - Code After Looper

I have a child thread running to do a task infinitely. I want to (1) constantly send data back to the UI thread, and (2) occasionally send data (corresponding to buttons) to the child thread to pause/continue the infinite task. My problem is that the child thread gets stuck in the looper, meaning the task does not execute.
My questions is this: How do I get the child thread to receive messages from the UI thread without blocking the infinite task?
This is what I have so far:
For task (1), I have a handler in my UI thread, which works, and an infinite loop in the child thread that sends back a message, which works by itself.
In UI thread:
mMainHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
b = msg.getData();
if (msg.what==1)
Log.i("main", "from child (running) - " + b.getBoolean("running"));
else if (msg.what == 2)
Log.i("main", "from child (count) - " + b.getInt("count"));
}
};
In child thread (currently using a dummy task until I get the framework worked out):
while (true) {
if (running) {
try {
curCount += up;
if (curCount == maxCount)
up = -1;
else if (curCount == minCount)
up = 1;
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e("", "local Thread error", e);
}
Bundle b = new Bundle(1);
b.putInt("count", curCount);
Message toMain = mMainHandler.obtainMessage();
toMain.what = 2;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
}
}
For task (2), I have a method in my UI thread corresponding to a button press that sends a message to the child thread, which works, and a handler in the child thread, which works by itself.
In UI thread:
private void sendRunning(boolean running) {
if (mChildHandler != null) {
Bundle b = new Bundle(1);
b.putBoolean("running", running);
Message msg = mChildHandler.obtainMessage();
msg.what = 1;
msg.setData(b);
mChildHandler.sendMessage(msg);
}
}
In child thread:
Looper.prepare();
mChildHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
if (msg.what==1){
b = msg.getData();
running = b.getBoolean("running");
Log.i(INNER_TAG, "from main (running) - " + b.getBoolean("running"));
Log.i(INNER_TAG, "running - " + running);
try {
Message toMain = mMainHandler.obtainMessage();
toMain.what = 1;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
} finally {}
}
}
};
Looper.loop();
Each one of those scenarios works fine alone, but trying to do both at the same time is the problem. If I put the infinite task after the Looper.loop(), it is never reached. If I put it before the Looper.prepare(), it is run once. If I put it withing the looper, it is still only run once.
Any ideas would be greatly appreciated :)
Here is my full code (minus package/imports) for reference:
public class MainActivity extends Activity {
Thread thread;
private Handler mMainHandler, mChildHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMainHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
b = msg.getData();
if (msg.what==1)
Log.i("main", "from child (running) - " + b.getBoolean("running"));
else if (msg.what == 2)
Log.i("main", "from child (count) - " + b.getInt("count"));
}
};
thread = new ChildThread();
thread.start();
// Get a reference to the button
Button buttonStart = (Button)findViewById(R.id.btnStart);
Button buttonStop = (Button)findViewById(R.id.btnStop);
// Set the click listener to run my code
buttonStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,
"Starting...", Toast.LENGTH_SHORT).show();
sendRunning(true);
}
});
buttonStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,
"Stopping...", Toast.LENGTH_SHORT).show();
sendRunning(false);
}
});
}
private void sendRunning(boolean running) {
if (mChildHandler != null) {
Bundle b = new Bundle(1);
b.putBoolean("running", running);
Message msg = mChildHandler.obtainMessage();
msg.what = 1;
msg.setData(b);
mChildHandler.sendMessage(msg);
}
}
#Override
protected void onDestroy() {
Log.i("tag", "stop looping the child thread's message queue");
mChildHandler.getLooper().quit();
super.onDestroy();
}
class ChildThread extends Thread {
private static final String INNER_TAG = "ChildThread";
private boolean running = true;
final int maxCount = 10;
final int minCount = 0;
public int curCount = minCount;
private int up = 1;
public void run() {
while (true) {
if (running) {
try {
curCount += up;
if (curCount == maxCount)
up = -1;
else if (curCount == minCount)
up = 1;
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e("", "local Thread error", e);
}
Bundle b = new Bundle(1);
b.putInt("count", curCount);
Message toMain = mMainHandler.obtainMessage();
toMain.what = 2;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
}
this.setName("child");
Looper.prepare();
mChildHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
if (msg.what==1){
b = msg.getData();
running = b.getBoolean("running");
Log.i(INNER_TAG, "from main (running) - " + b.getBoolean("running"));
Log.i(INNER_TAG, "running - " + running);
try {
Message toMain = mMainHandler.obtainMessage();
toMain.what = 1;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
} finally {}
}
}
};
Log.i(INNER_TAG, "Child handler is bound to - " +
mChildHandler.getLooper().getThread().getName());
Looper.loop();
}
}
}
}
Just Use Intent service rather then this thread so you can manage all UI of your update and what ever you want to do with UI in intent service one broadcast receiver is using and its very easy to handle threads and infect your your UI is nit hand or lock while your background process run .
I ended up just using a variable time for the thread to avoid the situation. Thanks for the advice.

Parent Activity not receiving Messages from Thread

My test app below is roughly based on this threads tutorial by Cristian Baita.
It works as expected, with the exception that the message sent from myThread's run() method is never received by the MainActivity's handler.
I am passing the MainActivity's handler to myThread in the thread's constructor. I then use that handler's sendMessage() method to send a message back to the MainActivity, but the handler never seems to receive it. Why is this?
Note: I've found using breakpoints for debugging in eclipse is a pain with threads, so I ended up going over the top with Log statments instead to help follow the apps execution.
I've put the full code at the end of this post, but to summarise:
The constructor for the MyThread class takes a handler from the calling activity as shown below.
public class MyThread extends Thread {
// Reference to mainHandler from the mainThread
private Handler parentHandler;
// Constructor
public MyThread(Handler pHandler) {
parentHandler = pHandler;
}
When I create the thread in MainActivity's onCreate() method I pass it the handler mainHandler:
myThread = new MyThread(mainHandler);
myThread.start();
Then in MyThread's run() method I have:
Message messageToParent = Message.obtain();
messageToParent.what = 2;
Log.i("myThread", "About to send message to parent ...");
parentHandler.sendMessage(messageToParent);
The message should then be received by mainHandler defined in MainActivity:
public Handler mainHandler = new Handler() {
public void handleMessages(Message msg){
Log.i("MainActivity", "Message Received");
switch(msg.what) {
case 2:
Log.i("MainActivity", "Handled message. msg.what = " + msg.what);
....
If you watch the LogCat window when this runs, you will see that MainActivity never logs "Message Received" or "Handled message... ". So the message never arrives at it's destination.
The MainActivity:
public class MainActivity extends Activity {
private MyThread myThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myThread = new MyThread(mainHandler);
myThread.start();
// Message the thread
Message msgToThread = Message.obtain();
msgToThread.what = 4;
Log.i("MainActivity", "About to send message to thread...");
myThread.getHandler().sendMessage(msgToThread);
}
public Handler mainHandler = new Handler() {
public void handleMessages(Message msg){
Log.i("MainActivity", "Message Received");
switch(msg.what) {
case 2:
Log.i("MainActivity", "Handled message. msg.what = " + msg.what);
// Message the thread
Message msgToThread = Message.obtain();
msgToThread.what = 6;
myThread.getHandler().sendMessage(msgToThread);
break;
default:
Log.i("MainActivity", "Unhandled message. msg.what = " + msg.what);
break;
}
}
};
}
The MyThread class:
public class MyThread extends Thread {
// Reference to mainHandler from the mainThread
private Handler parentHandler;
// Constructor
public MyThread(Handler pHandler) {
parentHandler = pHandler;
}
// Local handler for messages to this thread
private Handler myThreadHandler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what) {
case 4:
Log.i("myThread", "Handled message. msg.what = " + msg.what);
break;
case 6:
Log.i("myThread", "Handled message. msg.what = " + msg.what);
break;
default:
Log.i("myThread", "Unhandled message. msg.what = " + msg.what);
break;
}
}
};
#Override
public void run() {
super.run();
int count = 0;
boolean keepGoing = true;
try {
while(true) {
Log.i("myThread", "run() method - while loop is ticking ..." + count);
// some arbitrary conditions to make stuff happen
switch(count) {
case 5:
Message messageToParent = Message.obtain();
messageToParent.what = 2;
Log.i("myThread", "About to send message to parent ...");
parentHandler.sendMessage(messageToParent);
break;
case 10:
keepGoing = false;
break;
}
if(!keepGoing) {
Log.i("myThread", "myThread is going to stop");
break;
}
count++;
sleep(500);
}
}
catch (Exception e) {
Log.e("My Log", "Thread Loop Exception - " + e);
}
Log.i("myThread", "myThread has reached the end of it's run() method");
}
public Handler getHandler() {
return myThreadHandler;
}
}
From an initial look, it might be because your parent handler is private. change it to public and try once!
I've realized I misunderstood what we are doing when we write the handleMessage() method for our handler.
I thought we were writing a new method for the handler, so I named it something slightly different handleMessages() (notice the plural).
In fact what we are doing is overriding one of the handler's existing method.
In the sample code I was following, Cristian Baita does not use an #Override statement before his handleMessage() method. This is fair enough, since #Override is only a convenience for you and your compiler to highlight bugs. Embarrassingly it is my fault for assuming that because #Override wasn't there, we weren't overriding anything. Hopefully this slip up will help some others in their learning curve.
BTW: I would still thoroughly recommend Cristian Baita's 3 thread tutorials, as they are very clearly explained and easy to follow. The problem was mine, in making assumptions!

The difference between Handler.dispatchMessage(msg) and Handler.sendMessage(msg)

When I use Handler.dispatchMessage(msg), the handleMessage(Message msg) will be run on new thread but when I use Handler.sendMessage(msg), the handleMessage(Message msg) will be run on main thread. Who can tell me the difference between them?
Thanks!
Demo:
public class MainActivity extends Activity
{
private String TAG = "MainActivity";
private Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
Log.i(TAG, "Handler:" + Thread.currentThread().getId() + " & arg1=" + msg.arg1);
super.handleMessage(msg);
}
};
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i(TAG, "Main:" + Thread.currentThread().getId());
testMethod();
}
private void testMethod()
{
Thread thread = new Thread()
{
#Override
public void run()
{
Log.i(TAG, "Thread:" + Thread.currentThread().getId());
Message msg = mHandler.obtainMessage();
msg.arg1 = 1;
mHandler.dispatchMessage(msg);
Message msg2 = mHandler.obtainMessage();
msg2.arg1 = 2;
mHandler.sendMessage(msg2);
}
};
thread.start();
}
}
Output:
04-19 11:32:10.452: INFO/MainActivity(774): Main:1
04-19 11:32:10.488: INFO/MainActivity(774): Thread:8
04-19 11:32:10.492: INFO/MainActivity(774): Handler:8 & arg1=1
04-19 11:32:10.635: INFO/MainActivity(774): Handler:1 & arg1=2
mHandler.dispatchMessage(msg) is like directly calling handleMessage(Message msg) and I don't know when that would be useful. The point of Handlers is the ability to send messages to other threads. That's what you do with sendMessage.
Edit: as you can see it just calls handleMessage() for you.
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// callback = the Runnable you can post "instead of" Messages.
msg.callback.run();
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
If You Call the Handler.dispatchMessage() in the Main Thread Then The Message is processed in Main Thread.
If You Call The Handler.dispatchMessage() in the Worker Thread Then The Message is Processed in Worker Thread.
When You Call Handler.sendMessage(msg) The Message is Processed in the Thread Which Created The Handler.
The messages sent with Handler.sendMessage() will be handled on the thread you created in testMethod().
The messages sent with Handler.dispatchMessage() are handled on the main thread.

Message queue in android

can anybody tell me,
how can get data(message) from message queue ?
or how can send message from main thread to other thread ?.
Thanks
If you want to receive messages on a thread you should run a Looper and create a message Handler bound to this looper. The UI thread has a looper by default. There's a convenient class for creating threads with loopers called HandlerThread. Here's a good article about Handlers and Loopers: Android Guts: Intro to Loopers and Handlers.
EDIT:
HandlerThread thread = new HandlerThread("Thread name");
thread.start();
Looper looper = thread.getLooper();
Handler handler = new Handler(looper) {
#Override
public void handleMessage(Message msg) {
switch(msg.what) {
case SOME_MESSAGE_ID:
// SOME_MESSAGE_ID is any int value
// do something
break;
// other cases
}
}
};
handler.post(new Runnable() {
#Override
public void run() {
// this code will be executed on the created thread
}
});
// Handler.handleMessage() will be executed on the created thread
// after the previous Runnable is finished
handler.sendEmptyMessage(SOME_MESSAGE_ID);
not any other Thread.. you can sen it main Thread or Ui thread, using Handler..
create handler and send a runnable object as anarguement..
When an application first starts on a device
private final Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
if (WHAT == msg.what) {
textView.setMaxLines(msg.arg1);
textView.invalidate();
} else if (WHAT_ANIMATION_END == msg.what) {
setExpandState(msg.arg1);
} else if (WHAT_EXPAND_ONLY == msg.what) {
changeExpandState(msg.arg1);
}
super.handleMessage(msg);
}
};
You can use various technique to create a thread in android.
private void doAnimation(final int startIndex, final int endIndex, final int what) {
thread = new Thread(new Runnable() {
#Override public void run() {
if (startIndex < endIndex) {
// if start index smaller than end index ,do expand action
int count = startIndex;
while (count++ < endIndex) {
Message msg = handler.obtainMessage(WHAT, count, 0);
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendMessage(msg);
}
} else if (startIndex > endIndex) {
// if start index bigger than end index ,do shrink action
int count = startIndex;
while (count-- > endIndex) {
Message msg = handler.obtainMessage(WHAT, count, 0);
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendMessage(msg);
}
}
// animation end,send signal
Message msg = handler.obtainMessage(what, endIndex, 0);
handler.sendMessage(msg);
}
});
thread.start();
}
Please note: usually prepare() and loop() are already called in the Activity, so we should perform the following check:
if (Looper.myLooper() == null) {
Looper.prepare();
}

Thread problem in android?

Consider i have one thread as a separate class , for example SimpleThread.java,
class SimpleThread extends Thread {
public SimpleThread(String str) {
super(str);
}
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i + " " + getName());
try {
sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}
from my android home.java i need to start the thread,
new SimpleThread("Jamaica").start();
once the loop end i need to shoe the alert,but when i use
authalert = new AlertDialog.Builder(this);
it shows null pointer execption, i need a context over here in thread class , is there any other way to do this.
Hey you should use Handler for this
here is the code ...
ProgressDialog _progressDialog = ProgressDialog.show(this,"Saving Data","Please wait......");
settintAdater();
private void settingAdater(){
Thread _thread = new Thread(){
public void run() {
Message _msg = new Message();
_msg.what = 1;
// Do your task where you want to rerieve data to set in adapet
YourCalss.this._handle.sendMessage(_msg);
};
};
_thread.start();
}
Handler _handle = new Handler(){
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
_progressDialog.dismiss();
listview.setAdapter();
}
}
}
One way of solving your problem is using Handlers, as Sujit suggested. Other way is using AsyncTask. Read here.
the problem is : when you launch the thread, the Compiler will not wait until the thread finish his treatement , he will execute the next instruction ( authalert = new AlertDialog.Builder(this); )
so there are two or three ways to do this :
1) , use handler
2) define your own listener for your thread in order to listen until he finished his treatement ,
3) you can pass the Context of your activity , and at the last line of your run method , display the AlertDialog ( with Activity.runOnUiThread(new Runnable); )
You should read http://www.aviyehuda.com/2010/12/android-multithreading-in-a-ui-environment/ and http://developer.android.com/resources/articles/painless-threading.html
one way would be put a handler in your calling activity:
final mContext=this;
final Handler mHandler=new Handler(){
#Override
public void handleMessage(Message msg) {
int yourIntReturnValue=msg.what;
//cast your object back to whatever it was lets say it was a string:
// String yourString=(String) msg.obj;
//do something like authalert = new AlertDialog.Builder(mContext);
}
};
then
class SimpleThread extends Thread {
Handler mHandler;
public SimpleThread(String str, Handler h) {
super(str);
mHandler=h;
}
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i + " " + getName());
try {
sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
Message.obtain(mHandler, someIntRetValue,
"DONE" ).sendToTarget();
}
}

Categories

Resources