Skip to main content

Handling LWUIT Dialogs created by a background thread

2 replies [Last post]
fixpertise
Offline
Joined: 2012-12-14
Points: 0

I have written an application in LWUIT targeted for a J2ME phone (Sprint DuraXT). The application is for pickup and delivery van drivers. It receives dispatches from a back-end dispatching system that describe pickups and delivers the driver must make. As the drivers, execute the pickups and deliveries, the driver enters status information that is sent back to the dispatching system.

Now, during the processing of a pickup or delivery, the driver may be presented with error dialogs (incorrect field entry), yes/no confirmation dialogs (confirming some action) and information dialogs (indicating some status the driver should be aware of).

In addition, there is a background thread listening for dispatches coming from the back-end server. In the current implementation, this background thread can also create yes/no confirmation dialogs and information dialogs. These dialogs are more like an alert as they have an associated sound, but they are simply dialogs.

As long as these two dialogs do not occur “simultaneously” every thing works as expected. You can dismiss the dialogs and the app proceeds as expected.

However, when you are on a screen and there is a dialog already showing and a second one from the background thread occurs, you sometime wind up with the wrong screen showing and it is “frozen”. E.g. the soft keys have no effect.

My hypothesis is that there is a race condition between the threads that are dismissing the dialogs. It goes like this. The EDT is blocked showing the dialog that arises as part of the form’s logic. The background thread is also blocked showing a dialog. Now when the dialog showing on the EDT is dismissed, the form is restored, but the EDT may go off and display another form (via show()). When the dialog displayed by the background thread is dismissed, the form which was showing when the dialog was initially displayed is sometimes restored. Now, the display shows a different form than the one the EDT might have shown.

It is pretty clear that this problem is caused by the dialogs resulting from the activities of the background thread. So the basic question is: “How to handle the dialogs arising from the background thread?” I have some thoughts but none yield a particularly clean implementation. I am hoping somebody has had to deal with this same problem and has a suggestion.

I have tried synchronizing the dialog construction and display so that only one dialog can get displayed at a time. This certainly improves the UI, but does not fully resolve the problem. The race begins when the first dialog is dismissed. Here are some other ideas,

1. If a dialog is shown by a thread other than the EDT, call show on the form at the top of the display stack when the dialog is dismissed. This is a bit of a hack, but may be a workaround.
2. Run dialogs to be shown by the background thread on the EDT. There are several ways to do this, but the question is will it resolve the problem? Will using an EventDispatcher help? I have experimented using an EventDispatcher to fire an ActionEvent containing a subclass of a Dialog as a source. The subclass contains a show() method which invokes the correct form of the Dialog show method. The class holding the EventDispatcher (global to the application) listens for these events. When the event arrives, the show method is invoked. For information dialogs that simply continue execution from wherever they are dismissed, this should work. For yes/no dialogs, you may have to create something like yes/no callbacks to handle the bifurcation in the logic. And what is not obvious is if this will actually serialize the processing of the dialogs on the EDT thread. This seems complicated.

Any ideas?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
amuche
Offline
Joined: 2011-09-05
Points: 0

hi, you could actually create dialogs 'off' the edt iff you wish.
All you need do is ensure that the show() is synced on the edt.
used to xperience the race condtion before also, before i realised
a better way of handling it.
if u create a dialog in a separate thread, ensure that any of its show
method you call is synced with the edt.
you call sync anything on a separte thread with the edt by calling
lwuit callSerially() found on display.getInstance() class and
wrapping the action in its run method.

so generally I wud say;
you just need to sync on the edt when you show or change a current showing ui.
I would say every method that you expect to change something on the UI you are currently viewing.
for example:
if you have a Label on screen calling setText on that Label should be synced, if the Label is not currently on screen it doesn't matter.

fixpertise
Offline
Joined: 2012-12-14
Points: 0

I actually hit upon the solution you suggested after a bit of experimentation. I was happy to have you confirm it. I my case, the actions are more complicated than simple Dialogs and I found I had to wrap the whole action in a class which implements the Runnable interface. As you suggested, I run this via Display.getInstance().callSeriallyAndWait(runnable).

So others may benefit from this discussion, here is a example of one of these classes with the action embedded in the run method.

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

The key thing here is that the action contains logic depending on how a user responds to a yes/no Dialog and there are operations on an underlying database and messaging subsystem as well. Except for the Dialogs, nothing in this action blocks the EDT for more than a few 100s of milliseconds, so the application runs very smoothly.

Thanks for suggesting and confirming this approach