How can I write simple custom Android Handler class? - java

It's interesting for me how it's possible to write simple Android Handler class using only pure java to send signals from one thread to another?
I saw the source code:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android/os/Handler.java
But how for example to write class (Handler class) that can send for example int value from one thread to another(not using share data(like in Android Handler?))?

If you have the thread in the same method as the handler receiving the message you can do like this:
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do something
}
}
final Thread th = new Thread() {
public void run() {
// do something than send an integer - x in our case
int x = 0;
final Message msg = Message.obtain(handler, x, null);
handler.dispatchMessage(msg);
}
};
th.start();
If your handler can't be accessed directly from the thread than create a class extending Thread and pass the handler to the class's constructor.

This is how you can create your own CustomHandler like android handler by using only Java Api's .
private class CustomHandler {
private final Runnable POISON = new Runnable() {
#Override
public void run() {}
};
private final BlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<>();
public CustomHandler() {
initWorkerThread();
}
private void initWorkerThread() {
new Thread(new Runnable() {
#Override
public void run() {
Log.d("CustomHandler", "worker (looper) thread initialized");
while (true) {
Runnable runnable;
try {
runnable = mQueue.take();
} catch (InterruptedException e) {
return;
}
if (runnable == POISON) {
Log.d("CustomHandler", "poison data detected; stopping working thread");
return;
}
runnable.run();
}
}
}).start();
}
public void stop() {
Log.d("CustomHandler", "injecting poison data into the queue");
mQueue.clear();
mQueue.add(POISON);
}
public void post(Runnable job) {
mQueue.add(job);
}
}
And I would like to point at the question itself that you donot use handler to pass int values from one thread to another. Handlers are use to run tasks in another thread. If you want to share a variable between two threads, consider using volatile keyword and atomic variables.

Related

Can't stop thread

I have these two methods for creating and stopping a thread. However the thread still keeps running, even after the first method is called. (I'm creating an object of the class and calling them from another class).
private Thread thread;
public void stopAlarm() {
Log.i(LOG_TAG, "stopAlarm called");
sendAlarm = false;
if (!thread.equals(null)) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void triggerAlarm() {
Runnable alarmTest = new Runnable() {
#Override
public void run() {
while (sendAlarm) {
Log.i(LOG_TAG, String.valueOf(sendAlarm));
}
}
};
thread = new Thread(Test);
thread.start();
}
When stopAlarm is called the thread is always null, although it is called after triggerAlarm is called (thread is running).
Your problem is caused by thread scope. Thread scope is created when you create a thread with same variables in the scope but you can't change these variables from outside world. Best practice for managing runnables in android is to use Handler.
Handler handler = new Handler();
Runnable alarmTest = new Runnable() {
#Override
public void run() {
Log.i(LOG_TAG, String.valueOf(sendAlarm));
handler.post(alarmTest, 5000); //wait 5 sec and run again
//you can stop from outside
}
};
after definitions, in order to start the runnable:
handler.post(alarmTest,0); //wait 0 ms and run
in order to stop the runnable:
handler.removeCallbacks(alarmTest);
EDIT: wait statement with loop
EDIT: Complete solution
Handler handler = new Handler();
Runnable alarmTest = new Runnable() {
#Override
public void run() {
Log.i(LOG_TAG, String.valueOf(sendAlarm));
handler.post(alarmTest, 5000); //wait 5 sec and run again
//you can stop from outside
}
};
public void stopAlarm() {
Log.i(LOG_TAG, "stopAlarm called");
handler.removeCallbacks(alarmTest);
}
public void triggerAlarm() {
handler.post(alarmTest,0); //wait 0 ms and run
}
Depending on your OS you may find making your thread volatile may fix this.
private volatile Thread thread;
However - there are better ways to do this. One very useful one is using a small (just one entry) BlockingQueue which is polled by the running thread.
// Use a BlockingQueue to signal the alarm to stop.
BlockingQueue<String> stop = new ArrayBlockingQueue<>(1);
public void stopAlarm() {
stop.add("Stop");
}
public void triggerAlarm() {
new Thread(() -> {
try {
while (stop.poll(1, TimeUnit.SECONDS) == null) {
// Stuff
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
Clearly you will have to manage edge cases like where someone calls stopAlarm when no alarm is running.

Android JUnit: assert inside the handler

I am trying make a assert inside of handler but without success. I tried execute it with threads, runnables, etc. Next code is one example:
public class ServerTest extends AndroidTestCase {
private final String TAG = this.getClass().getSimpleName();
private final int ACK = 1;
public void testSendToServer(){
final ServerStub server = new ServerStub();
final CountDownLatch signal = new CountDownLatch(1);
new Thread(new Runnable() {
Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// This log never appear
Log.w(TAG, "handleMessage(Message "+msg+")");
assertEquals(ACK, msg.what);
signal.countDown();
return true;
}
});
#Override
public void run() {
// This log never appear
Log.w(TAG, "sentToServer()");
server.sentToServer(handler);
}
}).start();
try {
signal.await(15, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
//This assert fails
assertEquals(0, signal.getCount());
}
class ServerStub{
private final String TAG = this.getClass().getSimpleName();
public void sentToServer(Handler handler){
Message message = new Message();
message.what = ACK;
Log.i(TAG, "ACK_RECEIVED");
handler.sendMessage(message);
}
}
}
I want to test a method class that doesn't return nothing, just "do something" and return the response using a handler.
I execute the test case testSendToServer() with the next intention:
In this test a ServerStub is created that has a method sentToServer(Handler handler). In this method simply send an "ACK" message to the handler.
After that I create a CountDownLatch signal = new CountDownLatch(1); to call signal.countDown(); inside the handler handleMessage(Message msg) method to know if it is executed.
Continue with the test, I create a new Thread where a Handler is created and sentToServer(Handler handler) is called. Inside the Handler a assertEquals(ACK, msg.what); is called too where I need to know if the ServerStub sent me the "ACK".
Main Thread is waiting for 15 seconds or the signal.countDown(); is executed. Finally call assertEquals(0, signal.getCount()); to check if Handler was executed.
However the handler handleMessage(Message msg) method is never executed.
I read other posts and I tried a lot of examples, but I never found the answer.
Is it possible something like that?
More information:
Now I am trying create a handler inside a Thread, like this:
new Thread() {
#Override
public void run() {
Log.w(TAG, "Thread run");
Handler handler = new Handler(new Handler.Callback() {
...
}
}
}.start();
The log "Thread run" is printed but after that I get a "Test run failed: Instrumentation run failed due to 'java.lang.RuntimeException'".

Set boolean from outside Thread, inside the Thread-run

I've got a boolean outside the Thread. Then I use a method that requires a Thread around it that returns a boolean. How can I set the boolean outside the thread with the returned boolean?
Code:
// Handle Automatic E-Mail Sending in a new Thread
new Thread(new Runnable() {
#Override
public void run() {
// Since we want to display a Toast from within a different Thread,
// we need to use the runOnUiThread to display it
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(ChecklistActivity.cActivity, D.T_SENDING_EMAIL, Toast.LENGTH_LONG).show();
}
});
/*TODO: emailSuccessfullySent = */EMailSender.SendEmail();
}
}).start();
I've read somewhere I could do it with a final array like so:
final boolean[] array = new boolean[1];
// Handle Automatic E-Mail Sending in a new Thread
new Thread(new Runnable() {
#Override
public void run() {
// Since we want to display a Toast from within a different Thread,
// we need to use the runOnUiThread to display it
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(ChecklistActivity.cActivity, D.T_SENDING_EMAIL, Toast.LENGTH_LONG).show();
}
});
array[0] = EMailSender.SendEmail();
}
}).start();
emailSuccessfullySent = array[0];
But I find this rather odd. Is this the generally accepted way to set a value from within a Thread, or is there a better way to do this?
It requires a little more overhead, but the best way to approach this problem in Android is to use a Handler. A Handler is a structure which you can use to receive messages from multiple threads and execute code on the thread the Handler is defined in. By overriding the handleMessage(Message msg) method and defining a few constants, you can send messages from any thread and have them be handled in your UI thread.
Code:
public boolean variable = false;
private class MyHandler extends Handler {
public static final int MESSAGE_TOAST = 1;
public static final int THREAD_RETURN = 2;
public void handleMessage(Message msg){
if(msg.what == MESSAGE_TOAST){
Toast.makeText(msg.getData().getString("toast"), Toast.LENGTH_LONG).show();
} else if(msg.what == THREAD_RETURN){
variable = msg.getData().getBoolean("returnValue");
}
}
}
public MyHandler handler = new MyHandler();
This would make your thread look like this:
// Handle Automatic E-Mail Sending in a new Thread
new Thread(new Runnable() {
#Override
public void run() {
Bundle bundle = new Bundle();
bundle.setString("toast","I want to display this message");
Message msg = handler.obtainMessage(MyHandler.MESSAGE_TOAST);
msg.setData(bundle);
msg.sendToTarget();
bundle.setBoolean("returnValue", EMailSender.SendEmail());
msg = handler.obtainMessage(MyHandler.THREAD_RETURN);
msg.setData(bundle);
msg.sendToTarget();
}
}).start();
It's a little confusing when you start using Handlers, but once you get to know them, they are easy and very powerful.
There is nothing special about setting the value of a non-synchronized variable inside a Thread. Since your boolean is declared "outside" the scope of your Thread, what you have done is a perfectly acceptable way of doing it. The point here is the scope of the boolean. You don't need to use an array, though. And the final qualifier is simply because variables declared outside the scope of an inner class cannot be accessed if they are not final.

Android cancel Thread

I am doing a simple Async operation with Android, but since I want to execute the action couple of times, I am not using AsyncTask, I instead use Thread/Runnable mechanism with Handler to handle messages and staff. But at one point when I need to execute the second operation, I need to cancel the previous operation if it is still active.
I have something like this:
private void exec() {
new Thread(new Runnable() {
public void run() {
mBind.exec(3);
}
}).start();
}
Then in exec(int a) I have an interation like:
for(int i = 0; i<=res.lenght; i++) {
updateGui();
}
But at one point the exec() method is called for second time, and the gui is updated with the previous results too (I need only the results from the new (2nd) request).
I know there is way to do this with FutureTask and play with cancel() or with Thread's 'throw ThreadDead' exception, but I am just curious if I can do it the same way I started in the first place.
thanks!
What I have understand from your question is that you want to cancel the currently running thread if the new thread started.
This you can do by calling Thread's interrupt() method, this will interrupt the currently running thread, and throws the InterruptedException.
Thread t1 = null;
private void exec() {
t1 = new Thread(new Runnable() {
public void run() {
mBind.exec(3);
}
}).start();
}
Before calling exec, call t1.interrupt().
Feels a bit dirty, but could you save the name of the most recently activated Thread and check for it in your Handler? Something like:
private static final int MESSAGE_UPDATE_COMPLETE = 0;
private String threadName;
private void exec() {
Thread thread = new Thread() {
public void run() {
// do stuff
...
Message msg = Message.obtain();
msg.what = MESSAGE_UPDATE_COMPLETE;
msg.obj = this.getName();
handler.sendMessage(msg);
}
};
thread.start();
threadName = thread.getName();
}
...
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch(msg.what){
case MESSAGE_UPDATE_COMPLETE:
if (threadName.equals((String)msg.obj)) {
// do UI update
}
break;
...
}
}
}

How do I ensure another Thread's Handler is not null before calling it?

My program threw a NullPointerException the other day when it tried to use a Handler created on another thread to send that thread a message. The Handler created by the other thread was not yet created, or not yet visible to the calling thread, despite the calling thread having already called start on the other thread. This only happens very rarely. Almost every test run does not get the exception.
I was wondering what the best way is to avoid this problem for sure with minimal complication and performance penalty. The program is a game and very performance sensitive, especially once it is running. Therefore I try to avoid using synchronization after setup, for example, and would prefer to avoid spinning on a variable at any time.
Background:
In Android the Handler class may be used to "enqueue an action to be performed on a different thread than your own". Documentation here:
http://developer.android.com/intl/de/reference/android/os/Handler.html
The Handler must be created on the thread where it will be used. So creating it in the constructor of a thread, which is run by the thread creating that thread, is not an option.
When the Handler is for a thread other than the UI thread, the Looper class must also be used:
http://developer.android.com/intl/de/reference/android/os/Looper.html
The documentation gives this example of using the two classes for this purpose:
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();
}
}
My very ugly workaround currently looks like this:
public class LooperThread extends Thread {
public volatile Handler mHandler;
public final ArrayBlockingQueue<Object> setupComplete = new ArrayBlockingQueue<Object>(1);
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
setupComplete();
Looper.loop();
}
public void waitForSetupComplete() {
while ( true ) {
try {
setupComplete.take();
return;
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
private void setupComplete() {
while( true ) {
try {
setupComplete.put(new Object());
return;
} catch (InterruptedException e) {
//Ignore and try again.
}
}
}
}
With the code in the creating thread looking like this:
LooperThread otherThread = new LooperThread();
otherThread.start();
otherThread.waitForSetupComplete();
otherThread.mHandler.sendEmptyMessage(0);
Are there any better solutions? Thanks.
I'd go with the classic wait/notify
public class LooperThread extends Thread {
private Handler mHandler;
public void run() {
Looper.prepare();
synchronized (this) {
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
notifyAll();
}
Looper.loop();
}
public synchronized Handler getHandler() {
while (mHandler == null) {
try {
wait();
} catch (InterruptedException e) {
//Ignore and try again.
}
}
return mHandler;
}
}
Handler returned from getHandler can then be used many times without invoking synchronized getHandler.
Preparing a Looper can block for a while, so I imagine you're hitting a condition where prepare() takes a moment to complete, thus mHandler is still undefined.
You could have your Thread extend HandlerThread, though even then you still have to wait to ensure the Looper has initialised. Perhaps something like this might work, where you have the Handler defined separately, but utilising the Looper of your custom thread.
Maybe.
private void setUp() {
mHandlerThread = new CustomThread("foo", Process.THREAD_PRIORITY_BACKGROUND);
mHandlerThread.start();
// Create our handler; this will block until looper is initialised
mHandler = new CustomHandler(mHandlerThread.getLooper());
// mHandler is now ready to use
}
private class CustomThread extends HandlerThread {
public void run() {
// ...
}
}
private class CustomHandler extends Handler {
CustomHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// ...
}
}
I just want to add that the checked answer is the best one but if you test it like that is not going to work becouse you need to call super on run methode since it's in charge of preparing the looper so the code should be like this:
private void setUp() {
mHandlerThread = new CustomThread("foo", Process.THREAD_PRIORITY_BACKGROUND);
mHandlerThread.start();
// Create our handler; this will block until looper is initialised
mHandler = new CustomHandler(mHandlerThread.getLooper());
// mHandler is now ready to use
}
private class CustomThread extends HandlerThread {
public void run() {
super.run() // <- VERY IMPORTANT OTHERWISE IT DOES NOT WORK
// your code goes here
}
}
private class CustomHandler extends Handler {
CustomHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// ...
}
}

Categories

Resources