Java
 Computer >> コンピューター >  >> プログラミング >> Java

JavaのSwingWorkerクラスとは?GUIアプリで非同期処理を行う重要性と使い方を解説

SwingWorkerクラスは、時間のかかる処理(長時間実行タスク)などをワーカースレッド上で非同期に実行し、その結果に基づいてイベントディスパッチスレッド(EDT)からSwingコンポーネントを安全に更新するための仕組みを提供します。このクラスはJava 1.6で導入されました。

Swingでは、すべてのUI更新はEDT上で行う必要があります。しかし、EDT上で重い処理を直接実行すると画面がフリーズしてしまい、ユーザー体験を大きく損ないます。SwingWorkerを使えば、バックグラウンドでの処理とUIの更新を適切に分離できるため、応答性の高いデスクトップアプリケーションを実現できます。

SwingWorkerクラスの概要

  • javax.swing.SwingWorkerクラスは、時間のかかるタスクをバックグラウンドで実行する「タスクワーカー」です。
  • SwingWorkerのインスタンスは、現在のスレッド(Current thread)ワーカースレッド(Worker thread)イベントディスパッチスレッド(EDT)という3つのスレッドと連携します。
  • 現在のスレッドはexecute()メソッドを呼び出してタスクをバックグラウンドに投入し、すぐに制御を返します。
  • ワーカースレッドでは、オーバーライドしたdoInBackground()メソッドがバックグラウンドで継続的に実行されます。
  • EDTは定期的に起動し、ワーカースレッドでの進行状況を通知します。
  • doInBackground()が完了すると、EDTがオーバーライドしたdone()メソッドを呼び出して完了を通知します。
  • 中間結果を通知したい場合は、doInBackground()内でpublish(V)メソッドを呼び出します。するとEDTがオーバーライドしたprocess(List)メソッドを通じて値を受け取れます。
  • 進捗状況を更新したい場合は、doInBackground()内でsetProgress(i)メソッドを呼び出します。EDT側ではPropertyChangeListenerを実装することで変更通知を受け取れます。
  • JProgressBarクラスは、SwingWorkerインスタンスとして実装されたバックグラウンドタスクの進捗を表示するために設計されたUIコンポーネントです。

コード例

以下は、ボタンをクリックするとプログレスバー付きのダイアログを表示しながら、10秒間のタスクをバックグラウンドで実行するサンプルです。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SwingWorkerTest {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                JButton button = new JButton();
                button.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        new GUIWorker().execute();
                    }
                });
                button.setText("Click Me !!!");
                frame.getContentPane().add(button);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLocationRelativeTo(null);
                frame.setSize(350, 300);
                frame.setVisible(true);
            }
        });
    }
}

class GUIWorker extends SwingWorker {
    private JFrame frame = new JFrame();
    private JDialog dialog = new JDialog(frame, "Swingworker Test", true);
    private JProgressBar progressBar = new JProgressBar();

    public GUIWorker() {
        progressBar.setString("Waiting on time");
        progressBar.setStringPainted(true);
        progressBar.setIndeterminate(true);
        dialog.getContentPane().add(progressBar);
        dialog.setSize(350, 300);
        dialog.setModal(false);
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);
    }

    @Override
    protected Integer doInBackground() throws Exception {
        System.out.println("GUIWorker doInBackground()");
        Thread.sleep(10000);
        return 0;
    }

    @Override
    protected void done() {
        System.out.println("done");
        JLabel label = new JLabel("Task Complete");
        dialog.getContentPane().remove(progressBar);
        dialog.getContentPane().add(label);
        dialog.getContentPane().validate();
    }
}

実行結果

ボタンをクリックすると、不確定モードのプログレスバーを含むダイアログが表示され、バックグラウンドでタスクが実行されます。

JavaのSwingWorkerクラスとは?GUIアプリで非同期処理を行う重要性と使い方を解説

タスクが完了すると、done()メソッドがEDT上で呼び出され、プログレスバーが「Task Complete」というラベルに置き換わります。

JavaのSwingWorkerクラスとは?GUIアプリで非同期処理を行う重要性と使い方を解説

まとめ

SwingWorkerは、Java Swingアプリケーションにおける非同期処理の標準的なソリューションです。doInBackground()で重い処理を実行し、done()やprocess()でUIを安全に更新することで、EDTをブロックせずスムーズな操作性を実現できます。ファイル読み込み、ネットワーク通信、大量データの計算など、時間のかかる処理をGUIに組み込む際には必須のクラスといえるでしょう。

  1. JavaのGridBagConstraintsクラスとは?その役割と主なフィールドを徹底解説

    GridBagLayoutは、Java Swingで最も柔軟性の高いレイアウトマネージャーのひとつです。コンポーネント同士の相対的な位置関係を制約(constraints)を使って細かく指定できるのが最大の特徴です。GridBagLayoutは動的な矩形グリッド(セルの集まり)を内部に持ち、各コンポーネントは1つ以上のセルを占める「表示領域」に配置されます。そして、GridBagLayoutで管理されるすべてのコンポーネントには、その配置方法を定義するためのGridBagConstraintsインスタンスが関連付けられます。つまり、GridBagConstraintsは複雑なフォームレイアウト

  2. JavaのSwingUtilitiesクラスとは?invokeAndWait()とinvokeLater()で実現するスレッドセーフなGUI操作

    JavaのSwingでは、コンポーネントが画面に表示された後、それらを操作できるのは「イベントディスパッチスレッド(Event Handling Thread)」と呼ばれる単一のスレッドだけです。これはSwingの重要な設計原則であり、複数のスレッドから同時にGUIを操作すると不整合や予期しない動作が発生するため、すべての描画・更新処理をこのスレッドに集約することで安全性を確保しています。開発者は、別途作成したコードブロックの参照をイベントディスパッチスレッドに渡すことができます。SwingUtilitiesクラスには、そのための2つの重要なstaticメソッド、invokeAndWait()