Pages

Wednesday, June 04, 2014

Android AsyncTask dan Progress bar

Android AsyncTask ProgressBar sample img

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:
  1. Params, tipe parameter yang dikirim untuk dieksekusi di background.
  2. Progress, tipe parameter yang digunakan untuk menunjukan kemajuan sebuah operasi yang terjadi di background (biasanya digunakan untuk update ProgressBar).
  3. Result, tipe parameter yang akan digunakan untuk menampung hasil dari operasi yang terjadi di background.

AsyncTask dijalankan melalui 4 langkah:
  1. onPreExecute (), dipanggil pada UI thread sebelum sebuah tugas dijalankan. Langkah ini biasanya digunakan untuk inisialisasi tugas, misalnya menginisialisai sebuah ProgressBar dan menampilkannya pada UI.
  2. 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...).
  3. 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.
  4. 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.


Download: AsyncTaskProgressbarSample.zip (source-code), AsyncTaskProgressbarSample.apk (file apk).

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:

Android AsyncTask ProgressBar sample app img


Pada saat button "Open a File" dipilih:

Android AsyncTask ProgressBar sample app img


Pada saat sebuah file sedang dibaca di background:

Android AsyncTask ProgressBar sample app img


Pada saat operasi telah selesai dieksekusi (Finished)

Android AsyncTask ProgressBar sample app img


Pada saat operasi dibatalkan (Cancelled)

Android AsyncTask ProgressBar sample app img



No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...