Обратный вызов из другого потока вызывает исключение - PullRequest
1 голос
/ 05 мая 2010

Я пытаюсь создать простую многопользовательскую игру. Существует WorkerService, который должен обрабатывать все сетевые коммуникации и все взаимодействие между этой службой и моей деятельностью осуществляется с помощью AIDL. Я думаю, что это стандартный подход - для обеспечения двустороннего взаимодействия я использую также интерфейс IWorkerCallback (также AIDL).

Проблема в том, что обратные вызовы должны изменить вещи в пользовательском интерфейсе, что может быть сделано только в потоке пользовательского интерфейса. Я создал Handler (в потоке пользовательского интерфейса) и считаю, что это очевидное решение. Но, что удивительно, это не работает.

Мой LoungeActivity вызывает startServer() метод интерфейса IWorker. Соответствующий метод моего WorkerService делает некоторую работу и выполняет обратный вызов - это работает нормально. Затем WorkerService порождает новый поток, и обратный вызов из этого потока приводит к выдаче неверного исключения:

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

Вот код, проясняющий ситуацию:

startServer() реализация:

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 код:

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

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

    }
}

Каждый метод из callback выглядит так:

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

В методе обработчика handleMessage() я делаю простой switch(msg.what), и в каждом случае есть простая модификация пользовательского интерфейса (показ тоста, изменение текста и т. Д.).

Понятия не имею, почему выбрасывается это исключение. Мне удалось исправить его, упаковав код в Runnable и вызвав runOnUiThread(), но это все равно вызывает у меня любопытство - не должен ли обработчик всегда работать в потоке что создал это? А может я что-то не так делаю?

Ответы [ 3 ]

1 голос
/ 06 июля 2011

Я знаю, что это немного поздно, но проблема в том, что вы позвонили dispatchMessage().

Правильный метод: sendMessage().

dispatchMessage() вызовет handleMessage() в том же потоке.

Я предполагаю, что проблема не в том, что ваш обработчик находится в неправильном потоке, а в том, что пользовательский интерфейс пытается создать обработчик где-нибудь в вашем методе onHandle (). Поскольку onHandle () вызывается не в том потоке, вы получаете исключение.

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg)
{
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        handleMessage(msg);
    }
}
0 голосов
/ 01 октября 2010

Функция, которая изменяет пользовательский интерфейс, должна находиться в действии, которому принадлежит пользовательский интерфейс.

Эта ссылка поможет вам: http://android -developers.blogspot.com / 2009/05 / painless-threading.html

0 голосов
/ 05 мая 2010

Вы должны как-то вызвать вызывающую функцию из основного потока.

...