SwingWorker
From Wikipedia, the free encyclopedia
SwingWorkerは、サン・マイクロシステムズがJava言語のSwingライブラリ向けに開発した、一般的なユーティリティークラスであり、イベントディスパッチスレッドを適切に利用できるようにするものである。Java 6になって、JREに含まれるようになった。 SwingWorkerは、いくつかの非互換・非公式なバージョンが、1998年から2006年にかけて開発されてきた経緯があるため、これらのJava 6以前のバージョンに対する説明書を使わないよう注意を払うべきである。
イベントディスパッチスレッドの問題
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()を呼び出すと、件のタスクが完了するまでの間、再描画を含むすべてのイベントをブロックしてしまうため、長時間にわたるオペレーションの場合それが完了する前に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();
}
});