如何处理后台线程上显示的LWUIT对话框

时间:2012-12-14 22:54:10

标签: java-me dialog lwuit race-condition event-dispatch-thread

我在LWUIT中编写了一个针对J2ME手机(Sprint DuraXT)的应用程序。该应用程序适用于皮卡车和送货车司机。它接收来自后端调度系统的调度,该调度系统描述拾取并传递驱动程序必须进行的调度。作为驱动程序,执行拾取和交付,驱动程序输入发送回调度系统的状态信息。

现在,在处理提货或交货期间,可能会向驱动程序显示错误对话框(错误的字段输入),是/否确认对话框(确认某些操作)和信息对话框(指示驱动程序应该知道的某些状态)的)。

此外,还有一个后台线程正在侦听来自后端服务器的调度。在当前实现中,此后台线程还可以创建是/否确认对话框和信息对话框。这些对话框更像是一个警报,因为它们有相关的声音,但它们只是对话框。

只要这两个对话框没有“同时”发生,每个东西都按预期工作。您可以关闭对话框,应用程序按预期进行。

但是,当您在屏幕上并且已经显示一个对话框并且后台线程中出现了第二个对话框时,您有时会显示错误的屏幕并且它被“冻结”。例如。软键无效。

我的假设是线程之间存在争用对话框的竞争条件。它是这样的。 EDT被阻止,显示作为表单逻辑的一部分出现的对话框。后台线程也被阻止,显示一个对话框。现在,当EDT上显示的对话框被解除时,表单将被恢复,但EDT可能会关闭并显示另一个表单(通过show())。当后台线程显示的对话框被解除时,有时会恢复最初显示对话框时显示的表单。现在,显示屏显示的格式与EDT可能显示的格式不同。

很明显,这个问题是由后台线程活动产生的对话引起的。所以基本的问题是:“如何处理后台线程产生的对话框?”我有一些想法,但没有一个产生特别干净的实现。我希望有人不得不处理同样的问题并提出建议。

我尝试过同步对话框构造和显示,这样一次只能显示一个对话框。这肯定会改善UI,但不能完全解决问题。比赛在第一个对话框被解除时开始。以下是其他一些想法,

  1. 如果对话框由EDT以外的线程显示,则在取消对话框时,在显示堆栈顶部的表单上调用show。这有点像黑客,但可能是一种解决方法。
  2. 运行对话框,由EDT上的后台线程显示。有几种方法可以做到这一点,但问题是它会解决问题吗?将使用EventDispatcher帮助吗?我已经尝试使用EventDispatcher来触发包含Dialog的子类作为源的ActionEvent。子类包含一个show()方法,该方法调用Dialog show方法的正确形式。持有EventDispatcher的类(应用程序的全局)侦听这些事件。当事件到达时,将调用show方法。对于只是从被解雇的地方继续执行的信息对话,这应该有效。对于是/否对话框,您可能必须创建类似是/否的回调以处理逻辑中的分叉。而且显而易见的是,这是否会实际上序列化EDT线程上对话框的处理。这似乎很复杂。
  3. 有什么想法吗?

1 个答案:

答案 0 :(得分:1)

经过一些实验,我确实找到了解决方案。因为对话是涉及是/否对话和数据库查询的更加复杂的操作的一部分,我发现我必须将整个操作包装在实现Runnable接口的类中。然后我通过Display.getInstance()。callSeriallyAndWait(runnable)运行动作。

所以其他人可能会从这个讨论中受益,这里是其中一个类的示例,其中的操作嵌入在run方法中。

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

这里的关键是该操作包含逻辑,具体取决于用户如何响应是/否对话框以及底层数据库和消息传递子系统上的操作。除了Dialogs之外,此操作中没有任何内容阻止EDT超过几百毫秒,因此应用程序运行非常顺利。应用程序可以同时处理堆叠在彼此之上的dislogs,这是让这些操作在后台(非EDT)线程上运行的简单apporach的问题。