Secara ringkas, background worker yang akan diperlihatkan pada postingan ini adalah bagaimana menghentikan thread background worker yang sedang berjalan dan memulai kembali thread yang baru dalam satu tombol saja. Jika kita searching di om gugel kn umumnya pake dua tombol untuk start dan satunya lagi untuk stop, jadi untuk tiap event-eventya jadi mudah. Tapi klu cuma pke 1 tombol ceritanya agk beda dikit. Ok... Langsung saja kita buat project baru di visual studio :
Kemudian tambahkan 1 buah button, 1 textbox, 1 listbox, 1 progress bar, 1 label (tempatkan label di atas progress bar). Kemudian atur posisinya :
Kemudian nama dari masing-masing komponen saya ubah seperti terlihat di bawah :
Next, mari kita tambahkan handler buat tombol start. Untuk itu silahkan double klik tombolnya untuk melangkah ke file c#-nya. Emm... Sebelumnya tambahkan dulu variabel backgroudworker baru :
Di line number 23, dibuat variabel baru dengan nama worker. worker inilah yang akan kita gunakan untuk melakukan background process nantinya. Kemudian didalam fungsi startButton_Click(), tambahkan kode berikut {selalu perhatikan line number untuk setiap kode}:
Ketika button start di klik oleh user, maka pada line 34, variabel worker dicek, apakah sedang berjalan (kondisi busy) atau tidak. Nah jika worker tersebut mempunyai thread (sedang running), maka pada line 36, worker tersebut segera dihentikan dengan command "CancelAsync". Dengan dieksekusinya CancelAsync maka pada thread worker yang sedang running dapat mendeteksi jika thread ini harus dihentikan. Caranya diperlihatkan kemudian. Intinya worker.CancelAsync tersebut memberikan sinyal yang menunjukkan adanya perintah untuk menghentikan thread background worker yang sedang running. Kemudian pada line 39, kita membuat variabel baru dengan nama max tipe integer. Variabel max ini berguna untuk menyimpan angka yang dinput oleh user pada textbox (name="number") mainwindow. Angka dari textbox tersebut diambil dengan menggunakan fungsi Convert.ToInt32(). Fungsi convert tersebut ditambahkan eksepsi untuk menghandle user yang memasukkan selain angka pada textboxt. Eksepsinya seperti terlihat di atas yang terdiri dari format exception dan overflowexception. Format exception terjadi apabila user memasukkan huruf-huruf alphabet ke dalam textbox dan overflow exception terjadi apabila user memasukkan angka yang terlalu besar yang ukurannya tidak bisa ditampung pada variabel tipe integer di C#. Kemudian pada line 52, "Debug.Writeline(max)", kode ini hanya memperlihatkan nilai max ke dalam konsole output di visual studio. Terus pada line 54, "field.Items.Clear();", kode ini berguna untuk menghapus angka-angka pada listbox. Jadi setiap tombol startButton diklik, listboxnya akan dibersihkan hehe... :D. Nah kemudian pada line 56, worker kembali di cek, jika worker sedang tidak running, worker tersebut akan dirunning kembali dengan thread backgroundworker yang baru. Kode ini berguna ketika tombol start pertama kali diklik atau diklik setelah thread backgroundworker sudah selesai dijalankan, kondisi seperti itu kan tidak ada thread, jadi kode diline 58 dapat dieksekusi.
Next, ditambahkan 3 buah fungsi pendukung untuk background worker seperti terlihat di bawah :
Line 70 dibuat loop dari 0 sampai args. Loop ini adalah aktivitas utama yang dilakukan thread backgroundworker yang kita buat. Di dalam loop ini pertama kali dihitung presentasi yang akan ditampilkan pada progress bar dan label untuk presentasi progress bar. Yang perlu diperhatikan nilai i/args dikonvert ke double terlebih dahulu sebelum dikalikan 100. Hal ini untuk mencegah pembulatan yang akan menimbulkan progress bar menjadi tidak smooth.
Line 74, nilai i dicek dengan menggunakan modulo 2, jika 1 bagi 2 ternyata sisanya tidak sama dengan 0 berarti i tersebut adalah bilangan ganjil yang mengakibatkan pertambahan 1 angka pada mBilGanjil. Setelah itu di line 77, terdapat fungsi ReportProgress yang merupakan fungsi bawaan dari background worker yang berguna untuk memberikan sinyal kepada fungsi updateGUI untuk segera dijalankan. Jadi ketika fungsi ReportProgress dipanggil maka fungsi updateGUI akan dijalankan. Nah kita lihat di fungsi ReportProgress tersebut terdapat variabel input berupa presentasi dan i. Variabel presentasi nantinya akan digunakan untuk mengupdate tampilan pada progress bar dan presentasi label progress bar, sedangkan i adalah nilai bilangan ganjil yang nantinya akan ditampilkan pada listbox. Sebagai catatan, variabel input i tersebut boleh tidak berupa integer tapi berupa tipe data yang lain seperti string, char, double, float, byte, dsb.
Line 79 adalah handle untuk nilai i yang bukan bilangan ganjil. Urainnya hampir sama dengan kode blok di line 74, cuman di dalam kode else ini fungsi report progress hanya mengambil presentasi saja, karena jika i adalah bilangan maka kita tidak perlu menampilkan bilangan tersebut pada listboxt.
Line 84, thread dibuat sleep selama 13ms. Angka 13ms cuma coba-coba saja :D, silahkan gunakan angka yang lain sesuai dengan kebutuhan project yang dibuat. Yang perlu diperhatikan jika waktu sleep terlalu pendek maka updateGUI dapat mengalami masalah ketika mengupdate progress bar. Secara sederhana fungsi updateGUI butuh waktu beberapa milli sekon (mkn 12 - 17 ms tergantung tampilan GUI) untuk mengupdate GUI mainWindow, nah jika fungsi updateGUI tersebut belum selesai kemudian dia panggil lagi dari proses looping, berarti tar fungsi updateGUInya terlalu sibuk yang boleh jadi mengakibatkan aplikasi menjadi freeze. Makanya disini loopingnya di sleepkan dulu, biar fungsi updateGUI bisa selesai dengan tugasnya kemudian baru looping selanjutnya diproses :-). Nah itu kalo waktu sleepnya terlalu pendek, jika waktu sleep terlalu panjang otomatis update value diprogress bar terlihat agak lama dan membosankan, jadi pilih angka sleep yang pas untuk masing-masing aplikasi.
Line 87 - 91, ini adalah kode untuk mendeteksi sinyal cancel untuk menghentikan thread. Jika kembali melihat fungsi startButton_Click di line 36, disitu terdapat fungsi cancelAsync() yang telah dijelaskan sebelumnya bahwa fungsi cancelAsync tersebut berguna untuk memberikan sinyal untuk menghentikan thread background worker yang sedang berjalan. Nah sinyal dari cancelAsync ini diterima oleh fungsi cancellationPending yang menyebabkan e.cancel menjadi true (line 89), nilai true tersebut nantinya akan digunakan pada fungsi selesai() yang akan dijelaskan kemudian. Kemudian line 90, reportProgress diubah kembali menjadi nol, karena jelas thread ini harus dihentikan jadi progress barnya harus kembali di set ke nilai 0. Terus line 91, 'return', berarti fungsi threadProcess ini selesai yang mengakibatkan fungsi selesai() akan dijalankan dengan e.cancel bernilai true.
Line 97, terdapat fungsi ReportProgress kembali namun dengan nilai 100. Tentunya fungsi ini dapat dicapai jika proses looping telah selesai dan tidak ada sinyal untuk menghetikan thread, makanya nilainya 100. Kemudian line 98, e.Result = mBilGanjil, nah e.Result tersebut berarti menyimpan jumlah total bilangan ganjil yang dari selang 0 - args. e.Result ini akan digunakan oleh fungsi selesai() yang nantinya akan ditampilkan ke user. Kita lihat line 98 adalah kode terakhir dari fungsi threadProcess ini, berarti setelah itu fungsi selesai() akan dijalankan, namun dengan e.cancel = false.
Beralih ke fungsi updateGUI. Fungsi ini berguna untuk melakukan update terhadap item-item yang terdapat pada mainWindow aplikasi yang kita buat. Fungsi ini akan dijalankan ketika fungsi ReportProgress dieksekusi pada fungsi threadProcess. Seperti terlihat diatas, pada fungsi ReportProgress terdapat variabel input berupa presentasi dan nilai bilangan ganjil. Nah variabel-variabel tersebut akan digunakan lebih lanjut oleh updateGUI untuk menyesuaikan tampilan mainWindow yang lebih aktual.
Line 105, nilai progress bar diset sesuai dengan presentasi yang dimasukkan ke fungsi ReportProgress. Line 106 pun juga sama, cuman presentasinya ditampilkan pada label. Jadi selain progress bar yang terupdate kita juga dapat melihat presentasi progressnya.
Line 107, dilakukan pengecekan terhadap e.UserState. UserState sebenarnya menyimpan bilangan ganjil yang dimasukkan dari fungsi ReportProgress. Nah makanya disini dicek, kalo ada bilangan ganjil (e.UserState tidak bernilai 0), maka bilangan ganjil tersebut akan ditampilkan pada listboxt seperti yang dilakukan pada line 109.
Terakhir adalah fungsi selesai(). Seperti yang telah disebutkan sebelumnya, fungsi selesai() adalah fungsi yang baru akan dijalankan ketika fungsi threadProcess selesai atau eksekusi program keluar dari fungsi threadProcess. Sebagaimana diketahui, threadProcess diakhiri ketika ada perintah untuk menghentikan thread atau karena proses yang dikerjakan threadProcess (dalam hal ini mengecek dan menghitung bilangan ganjil) memang sudah selesai. Jadi dua kondisi tersebut akan dievaluasi di dalam fungsi selesai() ini.
Line 117, jika e.Cancelled bernilai true berarti menandakan bahwa fungsi threadProcess sebelumnya diakhiri karena adanya sinyal untuk menghentikan thread. Hal tersebut dapat dilihat pada line 89 di dalam fungsi threadProcess. Kemudian di line 119 - 134, kode programnya sama dengan line 34 - 59 yang mengambil bilangan inputan dari user kemudian dimasukkan ke variabel max yang kemudian dimasukkan kembali ke fungsi RunWorkerAsync(max){line 135} untuk memulai thread backgroundworker yang baru. Jadi secara sederhana, jika thread pertama di cancel maka thread kedua akan segera dijalankan sesaat setelah thread pertama berhenti tanpa menunggu user untuk mengklik tombol start. Nah makanya disini kita dapat menggunakan 1 tombol saja untuk menjalankan atau menghentikan thread yang sedang running.
Line 138, Di sini dideteksi jika fungsi threadProcess berhenti karena adanya error yang terjadi dalam sistem {error pada visual studio, error pada program, atw hardware pc, dsb...}. Jika ternyata error seperti ini terjadi maka akan dikeluarkan message seperti yang terlihat pada line 140.
Line 142 sampai terakhir adalah kode program yang akan dieksekusi jika fungsi threadProcess berhenti secara normal. Makanya di line 144 diperlihatkan jumlah bilangan ganjil yang telah dihitung. Jumlah bilangan ganjil tersebut diambil dari e.Result. Sebelumnya seperti terlihat pada line 98 di fungsi threadProcess, e.Result ini diassign mBilGanjil, sehingga pada fungsi selesai() nilai e.Result tersebut dapat digunakan kembali untuk ditampilkan ke user dengan menggunakan messageBox seperti pada line 144.
Nah sampai disini, kita telah membuat fungsi-fungsi yang nantinya digunakan untuk menjalankan backgroundworker sesuai dengan kebutuhan project yang sedang kita buat. Berikutnya adalah menghubungkan ketiga fungsi-fungsi diatas ke variabel worker. Untuk itu kembali ke fungsi public MainWindow() yang terletak dibaris-baris awal, kemudian tambahkan kode berikut :
public MainWindow() sebagaimana diketahui bersama adalah fungsi konstruktor, jadi didalam fungsi ini kita akan melakukan inialisasi variabel-variabel termasuk variabel worker yang telah dibuat. Line 28 adalah fungsi yang secara otomatis akan selalu ada karena digenerate secara otomatis oleh visual studio. Fungsi tersebut melakukan inisialisasi internal terhadap program kita seperti inisialisasi komponen-komponen pada file xml untuk GUI aplikasi. Kemudian line 30, variabel worker yang telah kita buat ditambahkan fitur reportprogress, Maksudnya worker ini dapat menggunakan fungsi ReportProgress yang telah dijelaskan sebelumya. Line 31, worker ditambahkan fitur yang dapat melakukan request untuk menghentikan thread. Jadi sekalipun didalam fungsi threadProcess terdapat kode untuk menghetikan thread, namun jika WorkerSupportCancellation tidak diset ke true, maka kode yang terdapat dalam fungsi threadProcess tersebut tidak akan berguna. Line 32, variabel worker diintegrasikan dengan fungsi threadProcess yang melakukan kegiatan utama dithread. Line 33, jika terdapat fungsi ReportProgress dari doWork, maka worker akan memanggil fungsi updateGUI, dan yang terakhir adalah jika workernya selesai maka fungsi selesa() akan dipanggil. So sampai disini kita bisa melihat semua fungsi-fungsi yang telah dibuat telah diintegrasikan. So... Jika programnya kita jalankan, hasilnya :
Kemudian pada textbox dimasukkan angka 678 terus tombol start ditekan hasilnya :
Nah ketika presentasi progress bar sekitar 58, angka pada textbox diganti, kemudian tombol start ditekan kembali sebelum presentasinya mencapai 100, maka progress bar akan start dari awal lagi. Jika kita kita tidak menggunakan kode untuk menghentikan thread backgroundworker yang sedang berjalan sekarang maka aplikasi ini akan membuat thread yang baru. So jika tombol start ditekan berulang-ulang, aplikasinya bisa freeze atau malah crash/not responding. Jadi terlihat, pentingnya untuk mengetahui teknik dalam menghentikan thread backgroundworker yang sedang running. :-)
Sekian...... semoga bermanfaat... :-)
No comments:
Post a Comment