Melakukan Tugas-tugas pada Service secara Asynchronous

Untuk menjalankan service yang memiliki pekerjaan yang banyak dan lama kita perlu menuliskan kode ke dalam thread yang terpisah. Berikut adalah latihan yang menunjukkan tugas-tugas dalam service secara asynchronous.

Masih menggunakan project dan file yang sama seperti latihan sebelumnya, kita modifikasi dan tambahkan kode pada file "MyService.java", seperti berikut:
package com.example.services;

import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

import java.net.MalformedURLException;
import java.net.URL;


public class MyService extends Service {

@Override
public IBinder onBind(Intent arg0) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*kita ingin agar service ini terus berjalan hingga
di-stop secara eksplisit, sehingga akan mengembalikan/return sticky
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show(); */
try {
new DoBackgroundTask().execute(
new URL("http://www.amazon.com/somefiles.pdf"),
new URL("http://www.wrox.com/somefiles.pdf"),
new URL("http://www.google.com/somefiles.pdf"),
new URL("http://www.diansano.blogspot.com/somefile.pdf"));

}
catch (MalformedURLException e) {
e.printStackTrace();
}
return START_STICKY;
}

private int DownloadFile(URL url) {
try {
/*men-simulasi beberapa saat untuk download file*/
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*mengembalikan angka sembarang yang menyejikam ukuran file yang di-download*/
return 100;
}

private class DoBackgroundTask extends AsyncTask {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalBytesDownloaded = 0;
for (int i = 0; i < count; i++) {
totalBytesDownloaded += DownloadFile(urls[i]);
/*menghitung persentase yang sudah di-download dan
menunjukan progressnya **/
publishProgress((int) (((i+1) / (float) count) * 100));
}
return totalBytesDownloaded;
}

protected void onProgressUpdate(Integer... progress) {
Log.d("Downloading files", String.valueOf(progress[0]) + "% downloaded");
Toast.makeText(getBaseContext(), String.valueOf(progress[0]) + "% downloaded",
Toast.LENGTH_LONG).show();
}

protected void onPostExecute(Long result) {
Toast.makeText(getBaseContext(), "Downloaded " + result + " bytes",
Toast.LENGTH_LONG).show();
stopSelf();
}
}

@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
}

Kemudian, kita jalankan di emulator pada Android Studio. Kemudian tekan tombol "Start Service", maka akan tampil pesan dari class 'Toast' yang menunjukkan persentase download yang sedang berjalan. Seharusnya akan tampil empat kali, yaitu: 25%, 50%, 75%, dan 100%. 

Kita juga bisa melihat tampilan output tersebut di jendela Log seperti berikut:
D/Downloading files: 25% downloaded
D/Downloading files: 50% downloaded
D/Downloading files: 75% downloaded
D/Downloading files: 100% downloaded

Penjelasan

Latihan ini mengilustrasikan suatu cara dimana kita bisa mengeksekusi suatu tugas secara asynchronous dalam suatu service. Kita membuatnya begitu dengan cara membuat 'inner class' yang menerapkan 'extends' class 'AsyncTask'. Class 'AsyncTask' ini memungkinkan kita melakukan eksekusi background tanpa perlu menangani thread secara manual.

Class 'DoBackgroundTask' menerapkan 'extends' class 'AsyncTask' dengan menetapkan tiga jenis generic:
private class DoBackgroundTask extends AsyncTask {
Dalam hal ini, ketiga jenis yang ditetapkan tersebut adalah URL, Integer dan Long. Ketiga jenis ini menentukan jenis data yang digunakan dengan mengikuti tiga method yang kita implementasikan dalam class 'AsyncTask':
  • doInBackground() -- Method ini menerima array dari generic yang pertama, dalam hal ini adalah URL. Method ini dieksekusi di thread background dimana kita menempatkan kode/tugas yang berjalan banyak/panjang. Untuk menunjukkan progress dari tugas tersebut, kita menggunakan method 'publishProgress()', yang mengaktifkan method berikutnya yaitu 'onProgressUpdate()', yang kita implementasikan dalam class 'AsyncTask'. Nilai kembalian/return dari method ini adalah generic yang ketiga, dalam hal ini yaitu 'Long'.
  • onProgressUpdate() -- Method ini diaktifkan di thread UI dan dipanggil bila kita memanggil method 'publishProgress()'. Method ini menerima array dari generic yang kedua, dalam hal ini yaitu 'Integer'. Kita menggunakan method ini untuk menampilkan progress di background kepada user.
  • onPostExecute() -- Method ini diaktifkan di thread UI dan dipanggil bila method 'doInBackground()' sudah menyelesaikan eksekusinya. Method ini menerima argument dari generic yang ketiga, dalam hal ini yaitu 'Long'.
Unyuk mendownload banyak file di background, kita membuat instans dari class 'DoBackgroundTask' dan kemudian memanggil method 'execute()' nya dengan melewatkan dalam array URL-URL seperti berikut:
try {
new DoBackgroundTask().execute(
new URL("https://phpisus.blogspot.com/somefiles.pdf"),
new URL("https://beritati.blogspot.com/somefiles.pdf"),
new URL("https://acollectionofjokes.blogspot.com/somefiles.pdf"),
new URL("https://diansano.blogspot.com/somefiles.pdf"));

}
catch (MalformedURLException e) {
e.printStackTrace();
}
Kode di atas menyebabkan service untuk mendownload file-file di background, dan menunjukkan progress dalam bentuk persentase dari file-file yang di-download. Hal yang lebih penting adalah bahwa 'activity' tetap berjalan dan bisa merespon sambil file-file di-download di background karena ada di thread yang terpisah.

Harap diperhatikan bahwa bila thread background sudah selesai mengeksekusi, kita bisa memanggil method 'stopSelf()' secara manual untuk menghentikan service:
protected void onPostExecute(Long result) {
Toast.makeText(getBaseContext(), "Downloaded " + result + " bytes",
Toast.LENGTH_LONG).show();
stopSelf();
}
Method 'stopSelf()' setara/sama dengan memanggil method 'stopService()' untuk menghentikan service.

1 comment:

Dony Nuransyah said...

maaf mas cmn mau ngasih saran klo bisa pasangin syntax highlighter di setiap ngasih contoh coding biar lebih ternotice dan enak di pandang. salam sukses