0

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?

mskw
  • 10,063
  • 9
  • 42
  • 64
  • @GabeSechan, yeah, I once tried some things with Android's built-in messages, but I either did it horribly wrong, or my memory of it didn't serve me well. It is indeed not a lot of boiler plate code. I would still recommend anyone to use [Otto](http://square.github.io/otto): it is a very nice event-bus for Android. – Bart Kiers Jul 14 '14 at 21:01
  • The question is if he needs that. Some things need an event bus. For others its horrible overkill. One thing that would concern me about Otto, for example, is that its synchronous. That's usually the opposite of what I want- if I want synchronous I wouldn't be using a thread. – Gabe Sechan Jul 14 '14 at 21:12
  • Fair enough, although Otto can easily be changed so that messages are posted and received on more than one thread, which is what I did. – Bart Kiers Jul 15 '14 at 09:30

2 Answers2

2

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();
        }
    }   
}
Community
  • 1
  • 1
Shobhit Puri
  • 25,769
  • 11
  • 95
  • 124
0

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.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • and that's why the google folks created a HandlerThread in order to avoid all of those steps – pskink Jul 14 '14 at 20:55
  • He'd still need to create the handler, either in the run function or elsewhere using the Looper from the HandlerThread as the Looper parameter in the constructor. So its 6 of one, half a dozen of the other in terms of work. But either way is fine, HandlerThread just didn't pop to mind, I've never actually used one. – Gabe Sechan Jul 14 '14 at 21:04
  • and the next question is: when can i use myHandler in order to send Messages? right after the thread is start()ed or i need to wait a while...? i hope you see the issue? – pskink Jul 14 '14 at 21:09
  • @pskink Same problem exists using HandlerThread. It still isn't valid to pass messages to the looper until loop is called- which happens at the end of the HandlerThread's run function. Just because its being done in the framework doesn't mean its not the same code. – Gabe Sechan Jul 15 '14 at 01:29
  • @pskink In fact I see a problem with using HandlerThread that a lot of newbies won't get- if you do try to create an actual handler to it, you need to do so after .start() is called. Otherwise the call to getLooper() will try to wait for the looper to be initialized (happens in run) and if the same thread expects to call start it deadlocks. I actually would never have expected that if I hadn't actually looked at the AOSP code. Which is why when things are 3 lines long I do it myself- so I knew what the issues are. – Gabe Sechan Jul 15 '14 at 01:33
  • @GabeSachan everybody knows that google is not the master when it comes to documentation, so this is the case, but if you 1) create a new HandlerThread() 2) start() it, 3) create a new Handler(ht.getLooper(), [Callback]) you are perfectly save, no other boilerplate synchronization code is needed – pskink Jul 15 '14 at 03:37
  • @pskink There actually still is a small timing gap. Look at the implementation of HandlerThread and you'll see it. It comes if the handler is created before the HandlerThread is scheduled (not started: scheduled by the kernel and run to the run function calls prepare). There's actually a 1 command gap after Looper.prepare and before the synchronized block as well. – Gabe Sechan Jul 15 '14 at 04:34
  • @GabeSachan you mean that you can send Messages to prepare()d Looper that is not yet loop()ing? – pskink Jul 15 '14 at 04:41
  • Yes. You can try, at least. I don't have any idea what the result would be. But Google has some timing bugs there. It can absolutely happen between lines 54 and 55 of HandlerThread.java if a context switch occurs to a thread that posts a message. – Gabe Sechan Jul 15 '14 at 04:47
  • It can also happen between lines 58 and 61, which are not in a synchronized block – Gabe Sechan Jul 15 '14 at 04:48
  • i tried that: its save, you can send Messages to not looping Looper, just its MessageQueue grows but will be finally reduced when Looper starts looping/consuming Messages – pskink Jul 15 '14 at 04:55
  • You're right. But then in my case there's also no problems- as soon as the handler is non-null you can post to it, because that thread has a looper as soon as you call prepare(), the messages will just be run as soon as loop() is called. – Gabe Sechan Jul 15 '14 at 05:06
  • sure thing, but still you have to synchronize your UI thread with a bckg one to make sure your handler is not null and its already done in HandlerThread – pskink Jul 15 '14 at 05:11
  • No, you don't need to synch the UI thread. Just only post if its not null. If it is null, then you don't post. Null checking doesn't require synchronization – Gabe Sechan Jul 15 '14 at 05:13
  • Or the answer I more frequently use (I gave this answer because he asked about Handlers specifically)- skip handlers alltogether and just use a synchronized queue object to communicate between threads. Then you don't need to deal with any synchronization or Handler objects or Loopers. They're really all overcomplications. – Gabe Sechan Jul 15 '14 at 05:18