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

Posted

技术标签:

【中文标题】如何处理后台线程上显示的 LWUIT 对话框【英文标题】:How to handle LWUIT dialogs shown on background threads 【发布时间】:2012-12-14 22:54:09 【问题描述】:

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

现在,在处理取件或交付过程中,可能会向驾驶员显示错误对话框(字段输入不正确)、是/否确认对话框(确认某些操作)和信息对话框(指示驾驶员应注意的某些状态)的)。

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

只要这两个对话框没有“同时”发生,一切都会按预期进行。您可以关闭对话框,然后应用按预期继续运行。

但是,当您在屏幕上并且已经显示了一个对话框并且出现了来自后台线程的第二个对话框时,您有时会以错误的屏幕显示而告终,并且它被“冻结”。例如。软键不起作用。

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

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

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

    如果对话框由 EDT 以外的线程显示,则在关闭对话框时在显示堆栈顶部的窗体上调用 show。这有点小技巧,但可能是一种解决方法。 在 EDT 上运行由后台线程显示的对话框。有几种方法可以做到这一点,但问题是它会解决问题吗?使用 EventDispatcher 会有帮助吗?我已经尝试使用 EventDispatcher 来触发包含 Dialog 的子类作为源的 ActionEvent。该子类包含一个 show() 方法,该方法调用正确形式的 Dialog show 方法。持有 EventDispatcher(应用程序全局)的类监听这些事件。当事件到达时,调用 show 方法。对于从被解散的任何地方继续执行的信息对话框,这应该有效。对于是/否对话框,您可能必须创建类似是/否回调来处理逻辑中的分叉。不明显的是,这是否真的会序列化 EDT 线程上的对话处理。这似乎很复杂。

有什么想法吗?

【问题讨论】:

【参考方案1】:

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

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

私有类 CancelOrder 实现 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 超过 100 毫秒,因此应用程序运行非常顺畅。该应用程序可以直接处理堆叠在一起的 dislog,这是让这些操作在后台(非 EDT)线程上运行的简单方法的问题。

【讨论】:

以上是关于如何处理后台线程上显示的 LWUIT 对话框的主要内容,如果未能解决你的问题,请参考以下文章

进度对话框和后台线程处于活动状态时如何处理屏幕方向更改?

离开 Activity 时 Android 如何处理后台线程?

如何处理Xcode上传IPA文件后无法在后台架构版本中显示的问题?

JS如何处理后台获取的Timestamp?

当应用程序不在后台运行时如何处理推送通知

在 Lwuit 中,如何处理键盘导航事件?