In this post I'll try to make a simple android app that uses AsyncTask to perform background operations and update the result on the UI through a Progress Bar.
For a better understanding of what exactly they are, you should read the AsyncTask explanations in here, and the progressBar in here.
In this sample app I just made the app to read a file. First, user will choose a file from the android storages, then the file will be sent to the AsyncTask to be read (reading operation is executed in the background). When the file is being read, AsyncTask will send the operation progress to the UI thread and show its progress on a ProgressBar, when the background operations is complete or the task has been cancelled, the progressBar will disappear (invisible). Finally, the result of the background operations will be shown through the TextViews.
The sample app was built using eclipse, java 1.7, and can run on Android 2.1 Eclair (API 7) - Android 4.4 KitKat (API 19).
Note:
- > The sample app uses a support library (android-support-v7-appcompat), see how to set up a support library on eclipse.
- > The sample app uses an implicit intent to choose an image or a video from the built in gallery app directly, to choose another file format (e.g .txt, .apk, and so on), then you need a third-party app such as a File Manager.
Download: AsyncTaskProgressbarSample.zip (source), AsyncTaskProgressbarSample.apk (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>
When you launch the sample app:
When the button "Open a File" was clicked:
When a file is being read in the background:
After completing the operation, show the final result to the user.
When the operation has been cancelled, show the final result to the user.











No comments:
Post a Comment