Lebih Dekat Dengan Class SwingWorker

Beberapa minggu terakhir ini, saya mendapatkan 2 pertanyaan tentang Bagaimana sih agar progress bar bisa berjalan pada saat proses Query ? dan Bagaimana sih cara membuat sebuah login dialog yang menampilkan progress bar ? Nah karena 2 pertanyaan tersebut saling berkaitan menurut saya (sama-sama ingin menjalankan Progress Bar pada saat aplikasi sedang menjalankan tugas/proses yang lain) maka akan saya jawab bersama-sama pada tulisan ini :) . Nah sebelum kita masuk ke penjelasan lebih detail, kita harus tahu dahulu dong kenapa kita tidak bisa secara langsung menjalankan progress bar di saat kita melakukan proses yang lain ? Ada yang tahu kenapa ? Ini karena semua “Event Handling” yang terdapat pada Java Swing dijalankan oleh Thread yang bernama Event Dispatch Thread (EDT) Waks.. Thread ? Yaps betul Thread :)

Agar aplikasi yang kita bangun di Java Swing tidak terlihat nge-“freeze” (tidak responsif/nge-hang), maka kita juga perlu tahu beberapa Thread yang terdapat di Java Swing. Thread-thread tersebut yaitu :

  1. Initial Thread
    Thread ini bertugas untuk menjalankan method main dari aplikasi Swing kita dan thread ini bertugas untuk menampilkan GUI (Graphical User Interface) yang sudah kita bangun diatas Swing ke layar. Setelah GUI (Graphical User Interface) tampil, maka kerja dari thread ini telah selesai dan akan dilanjutkan oleh Event Dispatch Thread.
  2. Event Dispatch Thread
    Setiap aplikasi berbasis Java Swing hanya dapat mempunyai 1 Event Dispacth Thread (EDT) saja. Setiap respon dari penekanan tombol, menu item, update tampilan komponen akan dijalankan oleh thread ini. Dan semua proses tersebut biasanya tidak membutuhkan waktu yang lama. Jadi, segala proses yang dijalankan pada thread ini harus selesai secepat mungkin agar aplikasi kita tidak terlihat nge-“freeze” (tidak responsif/nge-hang) .
  3. Worker Thread
    Worker thread atau biasanya disebut dengan background thread ini berfungsi untuk menjalankan proses yang lama seperti pembacaan direktori pada file system atau proses query ke database. Gunakan thread ini untuk melakukan operasi atau proses yang kita tidak bisa menentukan kapan kira-kira proses tersebut selesai.


Nah sekarang yang jadi pertanyaan yaitu apa hubungan-nya antara thread-thread diatas dengan class SwingWorker ? Ok untuk menjawab pertanyaan ini sekarang buatlah sebuah project di NetBeans IDE, kemudian buatlah sebuah JFrame dan design-lah JFrame tersebut seperti gambar dibawah ini :
DesignFrame
Design JFrame

Kemudian pada tombol Tampilkan Angka tambahkan kode seperti dibawah ini :

89
90
91
92
93
94
95
96
97
98
99
100
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
        jTextArea1.setText("");
        // jalankan progress bar
        jProgressBar1.setIndeterminate(true);
        for (int i=1; i<=5000;i++) {
            // Tampilkan angka satu persatu pada text area
            jTextArea1.append("Angka ke " + i + "\n");
        }
        // stop progress bar
        jProgressBar1.setIndeterminate(false);
        jTextArea1.append("\nDone ...");
    }

Setelah selesai, sekarang coba jalankan aplikasi-nya kemudian tekanlah tombol Tampilkan Angka dan jika tidak ada kesalahan maka kita akan mendapatkan tampilan seperti 2 gambar dibawah ini:

FreezeFrame
Tampilan Frame Nge-Freeze
AfterProses
Setelah Proses Looping

Pada tampilan diatas, kita bisa melihat bahwa GUI (Graphical User Interface) kita seakan-akan nge-freeze beberapa detik baru kemudian normal kembali dengan tiba-tiba menampilkan angka pada JTextArea. Hmmm koq aneh, padahal yang kita inginkan yaitu ketika proses perulangan berlangsung progress bar-nya berjalan dan angka akan ditampilkan satu persatu pada text area. Kenapa bisa seperti itu ?? Jawaban-nya adalah, karena kita melakukan proses perulangan dan meng-update tampilan (GUI) di dalam 1 thread yaitu Event Dispatch Thread (EDT). Sedangkan proses diatas, dapat kita gambarkan sebagai berikut :
flow_EDT
Flow EDT Ketika Penekanan Tombol, EDT Tidak Bisa Mengupdate Komponen

Note: Gambar diambil dan dimodifikasi dari http://java.sun.com/developer/technicalArticles/javase/swingworker/

Dari gambar flow EDT diatas, pada titik A itulah saat kita melakukan proses penekanan tombol Tampilkan Angka. Nah selama proses perulangan kita juga ingin meng-update tampilan dengan menampilkan angka satu persatu ke text area. Karena proses perulangan belum selesai, maka intruksi jTextArea1.append(“Angka ke ” + i + “\n”); ini tidak dapat dilakukan. Intruksi jTextArea1.append(“Angka ke ” + i + “\n”); ini baru berjalan ketika EDT sudah mencapai pada titik B.

Nah sekarang bagaimana caranya agar ketika kita melakukan per-ulangan, tampilan pada GUI juga ikut terupdate ? Solusi-nya yaitu dengan menggunakan Background Thread atau pada thread yang terpisah dari Event Dispatch Thread (EDT). Tujuan ini yaitu agar Event Dispatch Thread (EDT) dapat terus mengupdate GUI. Dan proses menjalankan Background Thread tersebut dapat kita jalankan ketika Event Dispatch Thread (EDT) berada pada Titik A atau ketika kita menekan tombol Tampilkan Angka. Dan proses ini dapat kita gambarkan seperti dibawah ini :
twothreads
Memisahkan EDT dengan Menggunakan Background Thread

Note: Gambar diambil dan dimodifikasi dari http://java.sun.com/developer/technicalArticles/javase/swingworker/

Mengenal SwingWorker Sebagai Solusi Background Thread

Untuk membuat sebuah Background Thread menggunakan class SwingWorker caranya sangat sederhana sekali yaitu buatlah sebuah class yang meng-extends class SwingWorker dan override-lah 1 buah method yaitu method doInBackground() seperti dibawah ini :

1
2
3
4
5
6
public class CobaWorker extends SwingWorker<t,V> {
	@Override
	protected <t> doInBackground() throws Exception {
		...
	}
}

Dimana T merupakan return type dari method doInBackground dan V adalah tipe yang akan digunakan oleh method publish dan process jika kita menggunakan method tersebut pada Background Thread kita. Sedangkan pada SwingWorker sendiri terdapat 3 thread yang mempengaruhi siklus kehidupan dari SwingWorker yaitu :

  • Current Thread
    Method SwingWorker.execute dipanggil dari thread ini. Thread ini mempunyai tugas untuk menjalankan “Worker Thread” saja.
  • Worker Thread
    Method SwingWorker.doInBackground ini dipanggil dari thread ini. Dan disini seharusnya semua Background Process dilakukan.
  • Event Dispatch Thread
    Semua aktifitas yang berkaitan dengan Java Swing dilakukan pada thread ini, thread ini juga akan memanggil method SwingWorker.done() dan SwingWorker.process()

Sedangkan untuk penggunaan standart-nya, kita sebenarnya hanya perlu meng-override method doInBackground saja. Dan jika proses yang dikerjakan oleh method doInBackground telah selesai maka method SwingWorker.done() akan dijalankan :)

Implementasi SwingWorker

Nah sekarang setelah mengetahui Basic Thread di Java Swing dan sedikit mengenal tentang SwingWorker terus sekarang bagaimana cara penggunaan-nya ? Sama seperti diatas, cara penggunaan-nya sangat sederhana sekali. Kopi-lah dahulu latihan pertama yang sudah kita buat di-awal kemudian gantilah nama filenya dengan WithBackgroundThread.java kemudian tambahkan-lah sebuah private class dengan nama WorkerLookup seperti dibawah ini :

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    private class WorkerLoop extends SwingWorker<string, Void> {
 
        @Override
        protected void done() {
            try {
                if (get() != null) {
                    jTextArea1.append(get());
                }
                // stop progress bar
                jProgressBar1.setIndeterminate(false);
            } catch (InterruptedException ex) {
                Logger.getLogger(WithBackgroundThread.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(WithBackgroundThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
 
        @Override
        protected String doInBackground() throws Exception {
            for (int i = 1; i <= 5000; i++) {
                // Tampilkan angka satu persatu pada text area
                jTextArea1.append("Angka ke " + i + "\n");
            }
 
            return "\nDone ...";
        }
    }

Penjelasan kode diatas yaitu :

  • Pada baris 102, kita membuat sebuah class dengan nama WorkerLoop yang meng-extends SwingWorker dengan parameter . Dimana String ini digunakan untuk menjelaskan tipe data apa yang akan dikembalikan oleh method doInBackground, karena pada class WorkerLoop ini tidak meng-override method proces maka kita bisa menggunakan tipe Void saja :)
  • Pada baris 120 inilah proses yang dijalankan pada Background Thread dilakukan, dan setelah method doInBackground ini selesai dijalankan maka kita akan mengirimkan pesan bertipe String ke method done()
  • Pada baris 105-117 ini kita gunakan untuk mengupdate GUI yang menandakan bahwa Background Process telah selesai dilakukan, dan kita dapat mengambil nilai yang dikirmkan oleh method doInBackground dengan menggunakan method get().

Setelah pembuatan WorkerLoop selesai, sekarang deklarasikan class WorkerLoop tersebut seperti dibawah ini:

22
23
24
25
26
27
28
29
30
31
32
public class WithBackgroundThread extends javax.swing.JFrame {
 
    // Deklarasikan WorkerLoop
    private WorkerLoop workerLoop;
 
    /** Creates new form OnEdtThread */
    public WithBackgroundThread() {
        initComponents();
    }
    ...
}

Kemudian langkah terakhir yaitu editlah kode yang terdapat pada tombol Tampilkan Angka hingga menjadi seperti dibawah ini :

94
95
96
97
98
99
100
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
        jTextArea1.setText("");
        // jalankan progress bar
        jProgressBar1.setIndeterminate(true);
        workerLoop = new WorkerLoop();
        workerLoop.execute();
    }

Sekarang coba jalankan dan tekanlah tombol Tampilkan Angka, seharusnya sekarang GUI kita sudah tidak nge-freeze ketika sedang melakukan perulangan dan progress bar-nya pun sudah bisa jalan dengan baik :) Mudah bukan ? Tapi yang perlu kita perhatikan ketika membangun aplikasi yang menggunakan Thread yaitu adalah berhati-hatilah dalam menggunakan-nya, karena sekali saja aplikasi terjadi kesalahan maka proses debugging-nya susah sekali :D

Dan dibawah ini adalah halaman-halaman referensi yang saya gunakan dan mohon maaf kalau ada salah kata/penyampaian :) :D
Link-link terkait :
- SwingWorker API JDK 1.6
- Penjelasan Tentang SwingWorker (WIKI)
-
Penjelasan Tentang EDT (WIKI)
-
Tutorial Concurrency di Java Swing
- Improve Application Performance With SwingWorker in Java SE 6
- Penjelasan Tentang Thread (WIKI)
- Milis NetBeans Indonesia
- Sample Project
- SubVersion Mudah Dengan RabbitVCS

  • Share/Bookmark
Print This Post

9 Responses to “Lebih Dekat Dengan Class SwingWorker”

  1. Request tutorial ?? Bisa om, asalkan saya sanggup saya tulis koq :D Apa sih yang enggak buat om ??? (Sembari colek2x om Dany) wkakakakakaakaka….. aw aw aw aw w :P

  2. newuser says:

    o gitu ya, o saya baru ingat ini dari java tutorial yang Concurrency in Swing.
    Tapi tetep penjelasan om martin lebih enak karena bahasa indo wkwkwkwk.

    Saya tunggu tutorial yang seperti ini lagi om.
    Dulu saya pernah request menu accordion. Bisa request lagi gak om.
    Buatin tutorial menu seperti start menu nya windows xp atau 7.

  3. newuser says:
    2010/04/14 at 3:40 PM

    penjelasan yg sangat sistematis. Tutorial indo terbaik yang pernah saya baca untuk penjelasan Thread di swing. Angkat topi untuk om martin kalo saya pake topi hehehe :D

    Btw, apa bener worker Thread itu termasuk thread yang ada di swing?

    :) ) kwkkwwk prikitiew deh om Dany, tutorialnya cuma translate dengan bahasa sendiri koq om :P kwkwkw untuk pemahaman saya pribadi juga :D . Klo untuk Worker Thread sendiri saya rasa koq itu cuma penamaan aja yah om (CMIIW) loh. Soalnya sebelum SwingWorker masuk ke JDK, dulu ada banyak implementasi Worker Thread untuk Java Swing (dugh lupa saya namanya apa ya, klo ga salah inget dulu ada 2 background thread yg khusus untuk Swing dan salah satu-nya SwingWorker ini).

    Kalau pemahaman saya gini, Worker Thread ini implementasi-nya bisa macam2x om. Mau bikin thread sendiri atau pakai class SwingWorker itu ga masalah, asalkan pisahkan proses yang membutuhkan waktu komputasi yg lama ini ke thread lain.

    Nah mungkin temen-temen dibawah saya bisa menambahkan kalau2x ada penjelasan yang bener tentang pertanyaan om Dany diatas :D (Ini masih asumsi saya pribadi loh om)

Leave a Reply

[+] adsenseid emoticons by Martinus Ady H. Modified from nartzco source code.