views:

131

answers:

2

I'm trying to create a simple multiplayer game. There's a WorkerService which is supposed to handle all network communication and all interaction between this service and my Activities is done with AIDL. I think this is a standard approach - to enable two way interaction I use also an IWorkerCallback interface (also AIDL).

The problem is that callbacks have to change things in UI which may be done only in UI thread. I've created a Handler (in UI thread) and believed that this is an obvious solution. But, surprisingly, it's not working.

My LoungeActivity calls startServer() method of IWorker interface. Corresponding method of my WorkerService does some job and makes a callback - this works fine. Then WorkerService spawns a new thread and callback from this thread results in a bad Exception being thrown:

Can't create handler inside thread that has not called Looper.prepare()

Here's some code to make it clear:

startServer() implementation:

private void startServerImpl(String name, float latStart, float latEnd,
float lonStart, float lonEnd)
{
    // some instructions here

    // this works fine:
    callback.notifySocketCreated();

    // my naughty thread:
    new ServerThread().start();

    // some instructions here
}

ServerThread code:

private class ServerThread extends Thread {
    @Override
    public void run()
    {
        //some instructions here

        // this call will cause an error
        callback.notifyGameRegistered();

    }
}

Every method from callback looks like that:

public void notifyGameRegistered() throws RemoteException
{
    handler.dispatchMessage(handler.obtainMessage(CALLBACK_GAME_REGISTERED));
}

In Handler's handleMessage() method I'm doing a simple switch(msg.what) and in every case there's a simple UI modification (showing a Toast, changing Text, etc.).

I have no idea why is this Exception thrown.. I've managed to fix it by packing code into a Runnable and calling runOnUiThread() but it still makes me curious - shouldn't a Handler always run in thread that created it? Or maybe I'm doing something wrong?

A: 

You have to somehow call the offending function from the main thread.

Lo'oris
Well.. I'm doing it now. But why is handleMessage executed in two different threads? Once it's in UI (notifySocketCreated()) and another time not (notifyGameRegistered()).
omarcin
A: 

The function that changes the UI should be in the activity that owns the UI.

This link should help you out: http://android-developers.blogspot.com/2009/05/painless-threading.html

Siddharth Iyer
Oh and I forgot to mention. The method should also be called from the activity that owns the UI
Siddharth Iyer
Thanks for the link but I've already seen it before. I believe that AsyncTask would be an overkill in described situation. It's not really important for me to find out how to fix my code (I remember that wrapping code in Runnables had helped), but I'm curious why one Handler instance once was in UI thread and another time it was not. Documentation says that "Each Handler instance is associated with a single thread and that thread's message queue."...
omarcin