Sekilas tentang AsyncTask
AsyncTask dapat digunakan pada saat sebuah aplikasi android di haruskan untuk melakukan operasi yang cukup lama (long-running operations), tugas atau task tersebut akan dikirimkan ke background thread untuk dieksekusi. Penggunaan AsyncTask berguna untuk menghindari masalah pada kecepatan UI, karena operasi tidak dijalankan di atas UI thread, melainkan pada thread terpisah (worker thread). Kemudian mempublikasikan hasil dari operasi di UI thread. AsyncTask dapat menjadi alternatif dari penggunaan Threads dan / atau Handlers. AsyncTasks sebaiknya digunakan untuk operasi yang singkat (kebanyakan hanya beberapa detik saja).
3 Parameter Generic AsyncTask:
- Params, tipe parameter yang dikirim untuk dieksekusi di background.
- Progress, tipe parameter yang digunakan untuk menunjukan kemajuan sebuah operasi yang terjadi di background (biasanya digunakan untuk update ProgressBar).
- Result, tipe parameter yang akan digunakan untuk menampung hasil dari operasi yang terjadi di background.
AsyncTask dijalankan melalui 4 langkah:
- onPreExecute (), dipanggil pada UI thread sebelum sebuah tugas dijalankan. Langkah ini biasanya digunakan untuk inisialisasi tugas, misalnya menginisialisai sebuah ProgressBar dan menampilkannya pada UI.
- doInBackground (params. ..), dipanggil pada background thread setelah method onPreExecute () selesai dieksekusi. Langkah ini digunakan untuk mengeksekusi sebuah long-running operations. Parameter AsyncTask (params) dilewatkan pada method ini, hasil operasi harus dikembalikan oleh method ini dan akan diteruskan kembali ke langkah terakhir (onPostExecute(Result)). Jika anda menggunakan ProgressBar untuk menampilkan kemajuan sebuah operasi yang terjadi di background, maka pada method ini anda dapat memanggil method publishProgress (Progress. ..) yang secara otomatis akan memanggil method onProgressUpdate (Progress. ..) yang berjalan pada UI thread. Selanjutnya anda dapat meng-update ProgressBar berdasarkan nilai-nilai yang diterima pada method onProgressUpdate(Progress...).
- onProgressUpdate (Progress. ..), dipanggil pada UI thread setelah method publishProgress (Progress. ..) selesai dieksekusi. Method ini digunakan untuk menampilkan segala bentuk kemajuan pada UI pada saat sebuah operasi masih berjalan di background.
- onPostExecute (Result), dipanggil pada UI thread setelah sebuah operasi yang terjadi di background telah selesai dieksekusi, hasil dari background operations akan diteruskan ke method ini sebagai parameter.
Sekilas tentang ProgressBar
ProgressBar digunakan sebagai Indikator visual dari kemajuan suatu operasi, menampilkan sebuah bar ke pengguna mewakili seberapa jauh operasi telah berkembang. Untuk menambahkan progress bar pada layout, Anda dapat menggunakan elemen <ProgressBar>. Jika anda ingin menunjukan kemajuan dari sebuah operasi yang telah diketahui, maka anda harus menggunakan progress bar horizontal, kemudian panggil method incrementProgressBy () atau setProgress () untuk menaikan nilai dari kemajuan suatu operasi. Untuk mengatur progress bar ke bar horizontal, anda dapat menggunakan atribut Widget.ProgressBar.Horizontal. Secara default, progress bar merupakan sebuah roda yang berputar (spinning wheel) dan bar penuh saat mencapai 100.
Implementasi AsyncTask dan ProgressBar pada Android
Dibawah ini merupakan contoh program android yang bernama "AsyncTaskProgressBarSample" yang mengimplementasikan AsyncTask dan ProgressBar pada android. User akan memilih sebuah file dari media penyimpanan, kemudian file tersebut akan dikirimkan ke AsyncTask untuk di baca (pembacaan file dilakukan pada background thread). Pada saat file sedang dibaca, AsyncTask akan mengirimkan kemajuan dari pembacaan file ke UI thread dan menampilkannya melalui ProgressBar. Setelah file selesai di baca atau proses pembacaan file di batalkan, secara otomatis progressbar akan menghilang, kemudian hasil dari operasi akan ditampilkan melalui TextView (lama operasi dan status operasi yang terjadi di background).
Program AsyncTaskProgressBarSample dibangun menggunakan Eclipse, Java 1.7, dan dapat berjalan diatas Android 2.1 Eclair (API 7) - Android 4.4 KitKat (API 19).
Note:
- AsyncTaskProgressBarSample menggunakan support library (android-support-v7-appcompat), lihat bagaimana cara setup support library.pada Eclipse disini.
- AsyncTaskProgressbarSample menggunakan implicit intent untuk memilih sebuah file image atau video dari Gallery built-in app secara langsung. Untuk memilih file format yang lainnya (misal, .txt, .apk, dan sebagainya), maka dibutuhkan aplikasi pihak ke-3 seperti File Manager.
src/com.me.asynctaskprogressbarsample/MainActivity.java
package com.me.asynctaskprogressbarsample; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends ActionBarActivity { private static final int REQ_CODE = 0; private ReadTask tasker; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { getSupportFragmentManager().beginTransaction() .add(R.id.container, new PlaceholderFragment()).commit(); } } /** * called when "Cancel button" is clicked it should abort the Asynctask * process */ public void cancelButton(View v) { // check is there any task that can be aborted if (tasker.getStatus() == AsyncTask.Status.RUNNING || tasker.getStatus() == AsyncTask.Status.PENDING) { // abort the task tasker.cancel(true); } } /** AsyncTask class used for reading a file <Params, Progress, Result> */ private class ReadTask extends AsyncTask<String, Integer, String> { // private String data; private String time; private int progressStatus; ProgressBar bar; TextView barPercent; Button openButton; Button cancelButton; TextView tv1; TextView tv2; @Override protected void onPreExecute() { super.onPreExecute(); // initial the Views bar = (ProgressBar) findViewById(R.id.progressbar); barPercent = (TextView) findViewById(R.id.barPercent); openButton = (Button) findViewById(R.id.openButton); cancelButton = (Button) findViewById(R.id.cancelButton); tv1 = (TextView) findViewById(R.id.textView1); tv1.setText("Elapsed: "); tv2 = (TextView) findViewById(R.id.textView2); tv2.setText("Status: "); // disable openButton openButton.setEnabled(false); // show the Views bar.setVisibility(View.VISIBLE); barPercent.setVisibility(View.VISIBLE); cancelButton.setVisibility(View.VISIBLE); progressStatus = 0; bar.setProgress(progressStatus); barPercent.setText("Reading... 0%"); } @Override protected String doInBackground(String... params) { // TODO Auto-generated method stub File file = new File(params[0]); int length = (int) file.length(); int i = 0; // j = 0; // byte[] temp = new byte[length]; InputStream in = null; byte[] buffer = new byte[8192]; try { in = new BufferedInputStream(new FileInputStream(file)); long start = System.currentTimeMillis(); while ((i = in.read(buffer)) != -1) { // temp[j++] = (byte) i; progressStatus += i; // update the progressbar publishProgress((int) ((progressStatus / (float) length) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } // data = byteToString(temp).toString(); time = ((System.currentTimeMillis() - start) + "ms").toString(); } catch (FileNotFoundException ex) { ex.printStackTrace(); time = ex.getMessage(); } catch (IOException ex) { // TODO Auto-generated catch block ex.printStackTrace(); time = ex.getMessage(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); time = e.getMessage(); } } } return time; } @Override protected void onProgressUpdate(Integer... progress) { super.onProgressUpdate(progress); // bar.incrementProgressBy(progress[0]); bar.setProgress(progress[0]); barPercent.setText("Reading... " + progress[0] + "%"); } @Override protected void onCancelled() { super.onCancelled(); // the task was cancelled // it's time to release resources results("-", "Cancelled"); } @Override protected void onPostExecute(String result) { super.onPostExecute(result); results(result, "Finished"); } void results(String e, String s) { // clean up the Tasker tasker = null; // enable the openButton openButton.setEnabled(true); // close the Views bar.setVisibility(View.GONE); barPercent.setVisibility(View.GONE); cancelButton.setVisibility(View.GONE); // update the TextView1 and TextView2 tv1.setText("Elapsed: " + e); tv2.setText("Status: " + s); } /** * called to cast byte array to String private String * byteToString(byte[] b) { char[] c = new char[b.length]; StringBuilder * sb = new StringBuilder(); * * for (int i = 0; i < c.length; i++) { c[i] = (char) b[i]; * sb.append(c[i]); } * * return sb.toString(); } */ } /** * check the AsyncTask status to make sure that the Tasker is ready to do * some task * * @return */ boolean gotStatus() { if (tasker == null || tasker.getStatus() == AsyncTask.Status.PENDING || tasker.getStatus() == AsyncTask.Status.FINISHED) { // initial the Tasker tasker = new ReadTask(); return true; } if (tasker.getStatus() == AsyncTask.Status.RUNNING) { // Tasker is still running // so we can't give it another task at the time return false; } return false; } /** called when button "Open a File" clicked */ public void openFile(View v) { // check the Tasker status // if true, it means Tasker ready to recieve a new task if (gotStatus()) { // we use implicit intent to get a file from the system (image, // video) // to select another file format (e.g .txt, .apk, and so on) // we need a third-party app such as a File Manager Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); intent.addCategory(Intent.CATEGORY_OPENABLE); try { startActivityForResult( Intent.createChooser(intent, "Select a file"), REQ_CODE); } catch (android.content.ActivityNotFoundException ex) { Toast.makeText(getBaseContext(), "You a need a File Manager", Toast.LENGTH_LONG).show(); ex.printStackTrace(); } } else { Toast.makeText(MainActivity.this, "Task is still Running", Toast.LENGTH_LONG).show(); } } @Override protected void onActivityResult(int reqCode, int resultCode, Intent data) { // check activity result base on reqCode // reqCode must be same as REQ_CODE switch (reqCode) { case REQ_CODE: if (resultCode == RESULT_OK) { // get Uri data from intent Uri uri = data.getData(); String path = null; try { // convert Uri to file path (String) path = getPath(getBaseContext(), uri); // send the task to the AsyncTask tasker.execute(path); } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } private static String getPath(Context context, Uri uri) throws URISyntaxException { if ("content".equalsIgnoreCase(uri.getScheme())) { String[] projection = { "_data" }; Cursor cursor = null; try { cursor = context.getContentResolver().query(uri, projection, null, null, null); int column_index = cursor.getColumnIndexOrThrow("_data"); if (cursor.moveToFirst()) { return cursor.getString(column_index); } } catch (Exception e) { e.printStackTrace(); } } else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } /** * A placeholder fragment containing a simple view. */ public static class PlaceholderFragment extends Fragment { public PlaceholderFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_main, container, false); return rootView; } } }
res/layout/activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.me.asynctaskprogressbarsample.MainActivity" tools:ignore="MergeRootFrame" />
res/layout/fragment_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.me.asynctaskprogressbarsample.MainActivity$PlaceholderFragment" > <Button android:id="@+id/openButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:onClick="openFile" android:text="Open a File" /> <LinearLayout android:id="@+id/linear" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/openButton" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="Elapsed: " /> <TextView android:id="@+id/textView2" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="Status: " /> </LinearLayout> <ProgressBar android:id="@+id/progressbar" style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignLeft="@id/linear" android:layout_below="@id/linear" android:visibility="invisible" /> <TextView android:id="@+id/barPercent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/linear" android:layout_below="@id/progressbar" android:visibility="invisible" /> <Button android:id="@+id/cancelButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/barPercent" android:layout_centerHorizontal="true" android:onClick="cancelButton" android:text="Cancel" android:visibility="invisible" /> <TextView android:id="@+id/attrs" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="15dp" android:text="@string/attrs" android:textStyle="bold" /> </RelativeLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.me.asynctaskprogressbarsample" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.me.asynctaskprogressbarsample.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Berikut tampilan program AsyncTaskProgressbarSample pada saat dijalankan:
Tampilan utama program:
Pada saat button "Open a File" dipilih:
Pada saat sebuah file sedang dibaca di background:
Pada saat operasi telah selesai dieksekusi (Finished)
Pada saat operasi dibatalkan (Cancelled)
No comments:
Post a Comment