2

私のアプリケーションは基本的にApacheのhttpclientを使用してサーバーに接続し、ユーザーのために何かをします。

私は Java の初心者 (開発の初心者ではありません) であるため、多くの Java 固有のアプローチは冷静に無視されてきた可能性があります。

説明

  • このアプリは、唯一のユーザー インターフェイスとしてポップアップ メニューを備えた TrayIcon を使用し、トレイ メッセージまたはポップアップ [確認] ダイアログに反応します。
  • 応答を待っているときにhttpclientがメインスレッドを効果的にブロックしていたため、スレッドを使用します
  • クライアントサーバーを使用して、単一のインスタンスのみを保証し、2 番目のインスタンスの試行に対する反応を保証します。
  • オブザーバー/オブザーバブル パターンを使用して、httpclient および単一インスタンス ウォッチドッグ サーバーのメッセージに反応します。
  • 主な動作は、唯一の Observer であるControllerクラスによって制御されます。httpclient に関連するものはすべて、Runnable を実装して Observable を拡張する別のWebClientクラスにあります。次に、再び Runnable および Observable であり、サーバー リスナーの周りのすべてを制御するAttServerがあります (実際にはそれほど多くはありません)。

これは Java での私の最初のアプリケーションです。

問題

望ましい動作は、ユーザーがこのアプリの 2 番目のインスタンスを実行しようとするたびに、ポート X でソケット リスナーをバインドしようとし、失敗するとそのポートに文字列メッセージを送信することです。「メイン」アプリはメッセージを受け入れ、確認ダイアログが表示されて反応し、ユーザーに何らかの入力を求めます。

クライアントサーバーを追加するまで、すべてがうまく機能していました。2 番目のインスタンスはオブザーバーの update() メソッドを正常にトリガーし、オブザーバーは何が起こっているかを正しく識別し、対応するメソッドを起動します。そして、最初の新しい GUI コンポーネント (確認ダイアログ) が表示される時点で、何も起こりません:

  • アプリは何もしません
  • System.out でスローされるエラーまたは例外はありません
  • トレイアイコンは引き続き正常に機能します(右クリックするとメニューなどが表示されます)

..ダイアログの後に来るすべての命令が実行されず、ダイアログが表示されないだけです。

奇妙さ #1

ユーザーがトレイ アイコン メニューを使用して、ダイアログを表示する他のコマンドを起動すると、GUI が何らかの理由でせき止められ、正しい順序で両方の (または適切な場合は複数の) ダイアログが表示されます (最初にスタックした非表示のダイアログが表示され、次に 2 番目の新しいダイアログが表示されます)。 1 つ) そして、すべてがこれが正しい状態であり、すべてのコマンドが正しく実行されているように見えます (一部のコマンドは「少し」後になりますが)。

奇妙#2

これは、スイングがスレッドと実際には互換性がないことが原因だと思います。ただし、update() メソッドが httpclient (これも別のスレッドです) から起動されると、GUI は問題なく動作します。オブザーバーが通知を受ける方法の唯一の違いは、WebClientがユーザー アクションの後で (別のスレッドで、(最悪の場合) 30 秒のタイムアウトの後ではあるが) notifyObservers() を呼び出し、AttServerが catch() ブロックで notifyObservers() を呼び出すことです。これは、指定されたポートが既にバインドされている場合に IOException がスローされるためです。

奇妙さ #3

この問題は控えめに言ってもイレギュラーです。これは通常、開発環境 (netbeans) で発生しますが、発生しない場合もあります --- 最初は、実際の問題のあるダイアログの前に、意図的に非表示のままにした別の (ダミー) JDialog を呼び出すことで解決されたという印象を受けました - -- スイングには少し「ドアから突き出す」必要があるように見えました。プロジェクトを(launch4j経由で)jarまたはexeにビルドした後、問題は戻ってきました。次に、すべてのスイングダイアログに単一のJFrameコンポーネントを使用しようとしましたが、何とか役立ちました---出力jarを実行すると、正常に動作し、翌日再びダイアログが非表示になることがあります。

私は完全に道に迷い、解決策を求めて地球を探し回りましたが、実際には何も見つかりませんでした。他の誰かが同様の問題に遭遇し、経験豊富な Javaman として解決策を見つけてくれることを願っています。また、メインの JFrame インスタンスで doLayout()、validate()、revalidate()、repaint()、update() 呼び出しをいくつか試しましたが、うまくいきませんでした。

希望があります:)読んでくれてありがとう、そしてどんなアイデアにも感謝します。

コード例

これはAttServerの run() 関数です-- 動作しない update() のソースです.. (主な機能がそこにあり、他の場所で行き詰まったため、少しハードコードされています..)

public void run() {

    this.addObserver( Controller.getInstance() );

    setChanged();

    // this.command == INIT set and new thread with AttServer called in the beginning of the main()
    if( null != this.command ) {

        switch( this.command ) {
            case INIT:
                try {
                    init();
                } catch( IOException ex ) {
                    notifyObservers( new ErrorEvent( 100 , "Could not bind the specified port." ) );
                }
            break;
            default:
        } //switch

    // no command, looks like an incoming connection
    } else {

        try {
            DataInputStream in = new DataInputStream( socket.getInputStream() );

            String inputLine;

            while( ( inputLine = in.readLine() ) != null ) {

                if( inputLine.trim().equals( EventType.CLOCKIN.toString() ) ) {

                    notifyObservers( EventType.CLOCKIN );

                    return;
                }
            }
        } catch( IOException ex ) {
            //todo
        }
    }
}

..これはフェンスの反対側である update() メソッドです。

public void update( Observable obj, Object arg) {
    // received a remote request *******************************************
    if( obj instanceof AttServer
        && arg instanceof EventType ) {

        EventType command = (EventType) arg;

        Attendance.debugMsg( "Received " + command.toString() + " request from AttServer" );

        if( false == isOnClock ) {
            doClock( true , true );
        }
    } // ..........

.. そして、これが update() から呼び出される doClock() メソッドの本質です。実際には何もありません。呼び出しの直後にダイアログが表示された場合や、update() メソッドでイベントが表示された場合でも、動作しません。

(overloaded with default data)
public static void doClock( Boolean clockIn , Boolean confirm , String message , String title ) {

    Event lastEvent = Log.getLastClock();

    if( confirm ) {
        if( JOptionPane.NO_OPTION == JOptionPane.showConfirmDialog( mainFrame , message , title , JOptionPane.YES_NO_OPTION ) ) {
            return;
        }
    }
4

1 に答える 1

5

このドキュメント全体を読まなければ (!!!)、 Event Dispatch Thread (EDT)を介して GUI を更新していないと思います。GUI は、EDTという単一のスレッドによって
のみ更新されると想定されています。アプリケーションでバックグラウンド スレッドを使用できますが、GUI の更新を EDTのみ に渡す必要があります。 独自のスレッド、つまり EDT 以外のスレッドで Swing コントロールに触れないでください。 そうしないと、たくさんの問題が発生します。 EDTを通過しないのは明らかに間違っています



于 2012-04-19T07:00:35.403 に答える