SwingWorker
SwingWorkerは、サン・マイクロシステムズがJava言語のSwingライブラリ向けに開発した、一般的なユーティリティークラスであり、イベントディスパッチスレッドを適切に利用できるようにするものである。Java 6になって、JREに含まれるようになった。 SwingWorkerは、いくつかの非互換・非公式なバージョンが、1998年から2006年にかけて開発されているが、Java 6に先行したこれらのバージョンに関して大量の記述を行うことは忌避すべきであろう。
目次 |
Java 6.0での使用 [編集]
イベントディスパッチスレッドの問題 [編集]
SwingWorkerが有効なのは、ユーザーインタラクションイベントに引き続いて、時間を要するタスクが実行されねばならない場合である(たとえば、JButtonを押下した後に巨大なXMLファイルをパース(構文解析)するなどの場合)。これを単純にコーディングすると、次のようになるが、
private Document doc; ... JButton button = new JButton("Open XML"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { doc = loadXML(); } });
これは動作はするものの、loadXML()メソッドがメインのSwingスレッドと同じスレッド(イベントディスパッチスレッド)の中で呼び出されることになるため、このメソッドの処理に時間がかかるなら、その間GUIはフリーズしてしまうことになる。
SwingWorkerのソリューション [編集]
この問題はJava固有のものではなく、多くのGUIモデルに共通して起こる問題である。SwingWorkerはこれを解決する手段として、時間を要するタスクを別のバックグラウンドスレッドで処理するようにしている。これにより、この間のGUIの反応は維持されるようになる。
ワーカーの作成 [編集]
次のコードは、loadXML()メソッドの呼び出しを包み込んだSwingWorkerを定義している。
SwingWorker worker = new SwingWorker<Document, Void>() { public Document doInBackground() { Document intDoc = loadXML(); return intDoc; } };
ワーカーの実行 [編集]
ワーカーの実行は、SwingWorker.execute()メソッドを使って開始できる。
結果の取得 [編集]
結果は、SwingWorker.get()メソッドを使って取得できる。 しかし、イベントディスパッチスレッド上でget()を呼び出すと、件のタスクが完了するまでの間、再描画を含むすべてのイベントをブロックしてしまうため、長時間にわたるオペレーションの場合それが完了するまえに呼び出されるのは忌避されるべきことになる。タスク完了後に結果を取得する方法は2つある。
SwingWorker.done()メソッドを上書きする。このメソッドは、メインのイベントディスパッチスレッドの中で呼び出される。
private Document doc; ... SwingWorker worker = new SwingWorker<Document, Void>() { public Document doInBackground() { Document intDoc = loadXML(); return intDoc; } public void done() { doc = get(); } };
SwingWorker.addPropertyChangeListener(PropertyChangeListener)メソッドを使ってリスナーを登録する。このリスナーには、ワーカーの状態の変化が通知される。
完全なワーカーの例 [編集]
private Document doc; ... JButton button = new JButton("Open XML"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SwingWorker<Document, Void> worker = new SwingWorker<Document, Void>() { public Document doInBackground() { Document intDoc = loadXML(); return intDoc; } public void done() { doc = get(); } }; worker.execute(); } });