Posting a Message to a running Thread using Handlers - android

I have code which calls a new Thread that connects to an IRC server. The thread has loop to listen for response from the IRC server and calls a method 'ProcessData' to action the response.
On my UI I want to be able to 'QUIT' the IRC server in onStop and onPause. The trouble I have is that when I use a Handler to post a message to my IRC thread which sends a QUIT command to the IRC server it tells me that I am performing network operations on the UI thread.
The handler is setup in my IRCManager class (this class extends Thread and is the class I run on a separate thread.
public Handler networkHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
try {
processData((String) msg.obj);
} catch (IOException e) {
Log.e(TAG, "network handler given an object NOT of type String");
}
super.handleMessage(msg);
}
};
I use the handler from the main activity and instantiate it just after starting the network thread
irc.start();
networkHandler = irc.networkHandler;
In the onPause event I send a message to the handler
Message msg = new Message();
msg.obj = IRCManager.QUIT;
networkHandler.sendMessage(msg);
EDIT: Here is the processData method
void processData(String data) throws IOException {
if (data.contains("PING")) {
String pingId = data.substring(6, data.length());
sendMessage(pong + pingId + "\n");
isConnected = true;
Message msg = new Message();
msg.what = 1;
msg.obj = "test";
handler.sendMessage(msg);
} else if (data.contains("Welcome")) {
sendMessage("PRIVMSG " + BOT_NAME + " JOIN " + siteId + "\n");
} else if (data.contains(IRCManager.QUIT)) {
disconnect();
} else if (isClientConnected()) {
Message msg = new Message();
msg.what = 2;
msg.obj = "test";
handler.sendMessage(msg);
}
}
It seems that the handler isn't linking properly to the thread. Can anyone shed any light on how I can do this?
My thread actually spends 99% of it's time in a while loop checking the inputstream from the IRC server. This may also have something to do with it.

You're creating the instance of the Handler, networkHandler, here:
public Handler networkHandler = new Handler() {
It'll be therefore associated with the UI thread.
And, when you say:
I use the handler from the main activity and instantiate it just after starting the network thread
irc.start();
networkHandler = irc.networkHandler;
You're not creating the instance of the Handler there; you're just grabbing a reference to it.
You actually need to create the instance of the Handler in the run() method of your non-UI Thread.

Try to use another constructor with new Handler(new Handler.Callback() ) inside

Related

Android : Message sent from seperate thread has obj set to null

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)
);

How do I receive a message using Handlers?

I've tried many ways to use handlers to receive messages on a background thread, I have not been successful.
Is there a sure fire way to test this? Is there a sample code I can use to see how it is done?
Yes, try the answer by #FoamyGuy. In the sample code he has sent back an empty message. I'm extending his code to pass strings. If you want to send some message back to the handler(eg: string), you can send some string or something else as follows:
Handler h = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 1){
//Success
String msg = (String)msg.obj;
Log.d("", "Msg is:"+msg);
}else{
//Failure
String msg = (String)msg.obj;
Log.d("", "Msg is:"+msg);
}
}
};
Thread t = new Thread() {
#Override
public void run(){
doSomeWork();
if(succeed){
//we can't update the UI from here so we'll signal our handler. and it will do it for us.
Message m = h.obtainMessage(1, "Success message string");
m.sendToTarget();
}else{
Message m = h.obtainMessage(0, "Your Failed!");
m.sendToTarget();
}
}
}
On a non-UI thread? All you need to do is create a Looper on that thread, then create the handler on it. That will automatically cause that Handler to be associated with that Looper. Then run Looper.loop
So
Looper.prepare();
Handler myHandler = new Handler();
Looper.loop()
and myHandler will be on the thread.

a handler is passed as parameter to the thread constructor and when tried to send message through the handler i am getting null pointer exception

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).

Passing a handler from a background Handler Thread, to background thread

Can anyone point me in the right direction here please ?
I have an activity which spawns two threads, a thread for handling messages, using a Looper
public static class MiddleThread extends Handler{
static public Handler handler;
public void run() {
Looper.prepare();
Log.d("MiddleThread", "Looper is prepared !");
handler = new Handler() {
public void handleMessage(Message msg)
{
Bundle bundle = msg.getData();
String exitString = bundle.getString("endmessage");
if(exitString.equals(("ExitOK")))
{
boolean searchFinished = true;
Looper looper = Looper.myLooper();
looper.quit();
} else
{
int fileCount = bundle.getInt("filecount");
String fileName = bundle.getString("filename");
Log.d("MiddleThread", "File Number " + fileCount + " is " + fileName);
}
}
};
Log.d("MiddleThread", "nandler should be initialised");
Looper.loop();
}
... then it spawns the main Worker Thread, which is passed a handler from the UI Thread, and the handler from the above thread.
public class BasicSearch {
public Handler handlerUi, handlerMiddleThread;
public Message messageUi, messageMiddleThread;
public int fileCount = 0;
public BasicSearch(Handler ui, Handler mt) {
handlerUi = ui;
handlerMiddleThread = mt;
}
public void listFiles()
{
File searchPath = Environment.getExternalStorageDirectory();
messageUi = handlerUi.obtainMessage();
messageMiddleThread = handlerMiddleThread.obtainMessage();
walk(searchPath);
Bundle b = new Bundle();
b.putString("endmessage", "ExitOK");
messageMiddleThread.setData(b);
handlerMiddleThread.dispatchMessage(messageMiddleThread);
}
private void walk(File path) {
File[] list = path.listFiles();
for(File f : list)
{
if(f.isDirectory())
{
walk(new File(f.getAbsolutePath()));
} else {
processFile(f);
}
}
}
private void processFile(File f) {
Bundle b = new Bundle();
fileCount++;
b.putString("filename", f.getName());
b.putInt("filecount", fileCount);
messageMiddleThread.setData(b);
Log.d("BasicSearch", "Data is set, to send to MiddleThread");
handlerMiddleThread.dispatchMessage(messageMiddleThread);
Log.d("BasicSearch", "Message sent");
}
}
Whatever happens, when it tries to dispatchMessage, handlerMiddleThread reverts to being null. I even have the following code in my activity, to try and ensure that it isn't null, but it still ends up being null when I get to send the message.
startMiddleThread();
while(true)
{
if(MiddleThread.handler != null)
break;
}
startSearchThread();
This is a test project, as I wanted to be able to get the Handler/Looper concept properly understood before continuing on with my project.
I have successfully managed to use a Handler in my UI Threads before, but my current project has too much processing going on in the UI, and I want to have a secondary thread handling the output from the searchThread, and just receive a message in UI thread when the thread is complete.
So I think I see what you're trying to do and let me suggest a slightly easier way:
To start your background thread and get a handler to it:
HandlerThread bgThread = new HandlerThread();
bgThread.start();
Handler bgHandler = new Handler(bgThread.getLooper());
Then you can send whatever messages you want to your bgHandler. Note that you need to call start on a HandlerThread before creating the bgThread (otherwise getLooper() will return null).
That being said I think I know whats wrong with your code as you posted it. First, MiddleThread extends Handler (which doesn't have a run() method!) not Thread. Second, the run() method on MiddleThread is never called, so Handler is never instantiated. Even if your just mistyped Handler in your code above and you're actually extending Thread, you still need to call start on MiddleThread in order for anything in run() to be executed. Really though, what you're doing is waaay more complicated that it needs to be, and you almost certainly want to just do what I mentioned above.

Android: Synchronize Methods on calling Remote Messenger Service

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.
}
}

Categories

Resources