Как обрабатывать диалоги LWUIT, отображаемые в фоновых потоках

Я написал приложение в LWUIT, предназначенное для телефона J2ME (Sprint DuraXT). Приложение предназначено для водителей пикапов и фургонов. Он получает депеши от внутренней диспетчерской системы, в которых описываются пикапы и доставки, которые должен сделать водитель. Когда водители выполняют погрузку и доставку, водитель вводит информацию о состоянии, которая отправляется обратно в диспетчерскую систему.

Теперь во время обработки самовывоза или доставки водителю могут быть представлены диалоги ошибок (неверный ввод в поле), диалоги подтверждения да/нет (подтверждение какого-либо действия) и информационные диалоги (указывающие на какой-то статус, о котором должен знать водитель).

Кроме того, существует фоновый поток, прослушивающий сообщения, поступающие с внутреннего сервера. В текущей реализации этот фоновый поток также может создавать диалоговые окна подтверждения «да/нет» и информационные диалоговые окна. Эти диалоги больше похожи на оповещение, поскольку у них есть соответствующий звук, но это просто диалоги.

Пока эти два диалога не появляются «одновременно», все работает, как и ожидалось. Вы можете закрыть диалоговые окна, и приложение продолжит работу, как и ожидалось.

Однако, когда вы находитесь на экране и уже отображается диалоговое окно, а возникает второе из фонового потока, вы иногда сталкиваетесь с отображением неправильного экрана, и он «зависает». Например. программные клавиши не действуют.

Моя гипотеза состоит в том, что между потоками, закрывающими диалоги, возникает состояние гонки. Это происходит так. EDT заблокирован, показывая диалог, который возникает как часть логики формы. Фоновый поток также заблокирован, показывая диалог. Теперь, когда диалоговое окно, отображаемое в EDT, закрывается, форма восстанавливается, но EDT может отключаться и отображать другую форму (через show()). Когда диалоговое окно, отображаемое фоновым потоком, закрывается, форма, которая отображалась при первоначальном отображении диалогового окна, иногда восстанавливается. Теперь на дисплее отображается форма, отличная от той, которую мог показать EDT.

Совершенно очевидно, что эта проблема вызвана диалогами, возникающими в результате действий фонового потока. Итак, основной вопрос: «Как обрабатывать диалоги, возникающие из фонового потока?» У меня есть некоторые мысли, но ни одна из них не дает особенно чистой реализации. Я надеюсь, что кто-то имел дело с этой же проблемой и имеет предложение.

Я попытался синхронизировать построение и отображение диалогового окна, чтобы одновременно отображалось только одно диалоговое окно. Это, безусловно, улучшает пользовательский интерфейс, но не решает проблему полностью. Гонка начинается, когда закрывается первый диалог. Вот еще идеи,

  1. Если диалог отображается потоком, отличным от EDT, вызовите show в форме в верхней части стека отображения, когда диалоговое окно будет закрыто. Это немного хак, но может быть обходным путем.
  2. Запустите диалоги, которые будут отображаться фоновым потоком в EDT. Есть несколько способов сделать это, но вопрос в том, решит ли это проблему? Поможет ли использование EventDispatcher? Я экспериментировал с использованием EventDispatcher для запуска ActionEvent, содержащего подкласс Dialog в качестве источника. Подкласс содержит метод show(), который вызывает правильную форму метода show Dialog. Класс, содержащий EventDispatcher (глобальный для приложения), прослушивает эти события. При наступлении события вызывается метод show. Для информационных диалоговых окон, которые просто продолжают выполнение с того места, где они были закрыты, это должно работать. Для диалогов да/нет вам, возможно, придется создать что-то вроде обратных вызовов да/нет, чтобы справиться с бифуркацией в логике. И что не очевидно, так это то, будет ли это на самом деле сериализовать обработку диалогов в потоке EDT. Это кажется сложным.

Любые идеи?


person Andy    schedule 14.12.2012    source источник


Ответы (1)


Я на самом деле наткнулся на решение после небольшого эксперимента. Поскольку диалоги являются частью более сложного действия, включающего диалоги «да/нет» и запросы к базе данных, я обнаружил, что мне нужно обернуть все действие в класс, который реализует интерфейс Runnable. Затем я запускаю действие через Display.getInstance().callSeriallyAndWait(runnable).

Так что другим может быть полезно это обсуждение, вот пример одного из этих классов с действием, встроенным в метод запуска.

   private class CancelOrder implements Runnable {

    private KWMap order;

    public CancelOrder(KWMap order) {
        this.order = order;
    }

    public void run() {
        String orderNum = getString(order, OrderTable.ORDER_NUM);
        if (legStatusTable.isOrderStarted(orderNum)
                && !orderTable.isOrderComplete(order)) {
            String msg = "You received a cancellation message for Order "
                    + orderNum
                    + " which has been started but is not finished."
                    + "\nDo you want to keep it?";
            if (app.yesNoDialog(msg, "Yes", "no")) {
                sendCancelResponse(order, "Yes", "");
            } else {
                deleteOrder(orderNum);
                sendCancelResponse(order, "No", "");
            }
        } else {
            // order has neither been started nor completed.
            deleteOrder(orderNum);
            sendCancelResponse(order, "Yes", "");
            app.alertDialog("Dispatcher cancelled Order " + orderNum);
        }
    }
}

Ключевым моментом здесь является то, что действие содержит логику в зависимости от того, как пользователь отвечает на диалоговое окно «да/нет», а также есть операции с базовой базой данных и подсистемой обмена сообщениями. За исключением диалогов, ничто в этом действии не блокирует EDT более чем на несколько сотен миллисекунд, поэтому приложение работает очень плавно. Приложение корректно обрабатывает наложение дислогов друг на друга, что было проблемой при простом подходе к запуску этих действий в фоновом (не EDT) потоке.

person Andy    schedule 19.12.2012