2

J2ME 電話 (Sprint DuraXT) を対象とした LWUIT でアプリケーションを作成しました。このアプリケーションは、集荷および配達のバンドライバー向けです。バックエンド配車システムから配車を受け取り、ドライバーが行う必要がある集荷と配達を記述します。ドライバーが集荷と配送を実行すると、ドライバーはステータス情報を入力し、それが配車システムに送り返されます。

現在、集荷または配達の処理中に、エラー ダイアログ (フィールド入力の誤り)、はい/いいえの確認ダイアログ (何らかのアクションの確認)、および情報ダイアログ (ドライバーが認識しておく必要のあるステータスを示す) がドライバーに表示される場合があります。

さらに、バックエンド サーバーからのディスパッチをリッスンするバックグラウンド スレッドがあります。現在の実装では、このバックグラウンド スレッドは、yes/no 確認ダイアログと情報ダイアログも作成できます。これらのダイアログは、サウンドが関連付けられているためアラートに似ていますが、単なるダイアログです。

これら 2 つのダイアログが「同時に」発生しない限り、すべてが期待どおりに機能します。ダイアログを閉じると、アプリは期待どおりに進みます。

ただし、ある画面にすでにダイアログが表示されていて、バックグラウンド スレッドからの 2 番目のダイアログが発生すると、間違った画面が表示されて「フリーズ」することがあります。たとえば、ソフトキーは無効です。

私の仮説は、ダイアログを閉じているスレッド間に競合状態があるというものです。こんなふうになります。EDT がブロックされ、フォームのロジックの一部として発生するダイアログが表示されます。バックグラウンド スレッドもブロックされ、ダイアログが表示されます。EDT に表示されているダイアログが閉じられると、フォームは復元されますが、EDT がオフになり、別のフォームが表示される場合があります (show() を介して)。バックグラウンド スレッドによって表示されたダイアログを閉じると、ダイアログが最初に表示されたときに表示されていたフォームが復元される場合があります。ここで、ディスプレイは、EDT が示したものとは異なるフォームを示します。

この問題が、バックグラウンド スレッドのアクティビティから生じるダイアログによって引き起こされていることは明らかです。基本的な質問は、「バックグラウンド スレッドから発生するダイアログをどのように処理するか」です。私にはいくつかの考えがありますが、特にクリーンな実装をもたらすものはありません。誰かがこの同じ問題に対処しなければならず、提案があることを願っています。

一度に 1 つのダイアログのみが表示されるように、ダイアログの構築と表示を同期させようとしました。これにより、UI は確実に改善されますが、問題が完全に解決されるわけではありません。レースは、最初のダイアログが閉じられたときに始まります。その他のアイデアはこちら、

  1. ダイアログが EDT 以外のスレッドによって表示されている場合は、ダイアログが閉じられたときにディスプレイ スタックの一番上にあるフォームで show を呼び出します。これはちょっとしたハックですが、回避策になる可能性があります。
  2. EDT のバックグラウンド スレッドによって表示されるダイアログを実行します。これを行うにはいくつかの方法がありますが、問題はそれで問題が解決するかどうかです。EventDispatcher を使用すると役立ちますか? EventDispatcher を使用して、Dialog のサブクラスをソースとして含む ActionEvent を起動する実験を行いました。サブクラスには、ダイアログの show メソッドの正しい形式を呼び出す show() メソッドが含まれています。EventDispatcher (アプリケーションに対してグローバル) を保持するクラスは、これらのイベントをリッスンします。イベントが到着すると、show メソッドが呼び出されます。閉じられた場所から単に実行を継続する情報ダイアログの場合、これは機能するはずです。yes/no ダイアログの場合、ロジックの分岐を処理するために yes/no コールバックのようなものを作成する必要がある場合があります。そして、これが実際に EDT スレッドでのダイアログの処理をシリアル化するかどうかは明らかではありません。これは複雑に思えます。

何か案は?

4

1 に答える 1

1

私は実際に少し実験した後、解決策にたどり着きました。ダイアログは、yes/no ダイアログとデータベース クエリを含むより複雑なアクションの一部であるため、Runnable インターフェイスを実装するクラスでアクション全体をラップする必要があることがわかりました。次に、Display.getInstance().callSeriallyAndWait(runnable) を介してアクションを実行します。

他の人もこの議論から恩恵を受けるかもしれません.runメソッドにアクションが埋め込まれたこれらのクラスの1つの例を次に示します.

   プライベート クラス 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);
        }
    }
}

ここで重要なことは、ユーザーが yes/no Dialog にどのように応答するかに応じて、アクションにロジックが含まれており、基礎となるデータベースとメッセージング サブシステムにも操作があるということです。ダイアログを除いて、このアクションでは数百ミリ秒以上 EDT をブロックするものは何もないため、アプリケーションは非常にスムーズに実行されます。アプリは、互いの上に積み重ねられた dislogs を coorectly 処理します。これは、これらのアクションをバックグラウンド (非 EDT) スレッドで実行させる単純なアプローチの問題でした。

于 2012-12-19T16:40:39.617 に答える