Android Asynctask Detailed

Source: Internet
Author: User

There are two ways to implement the asynchronous task mechanism in Android, Handler and Asynctask.

Handler mode needs to create a new thread for each task, after the completion of the task through the handler instance to the UI thread to send messages to complete the interface update, this way for the entire process of control is relatively fine, but also has shortcomings, such as the relatively bloated code, when more than one task at the same time, Precise control of the thread is not easy. About handler related knowledge, the front also has introduced, unclear friends can refer to.

To simplify the operation, Android1.5 provides the tool class Android.os.AsyncTask, which makes it easier to create asynchronous tasks, eliminating the need to write task threads and handler instances to accomplish the same tasks.

First look at the definition of Asynctask:
Public abstract class Asynctask<params, Progress, result> {
}

Three generic types represent the input parameters for starting task execution, the progress of background task execution, and the type of background calculation results, respectively. In certain situations, not all types are used, and if they are not used, they can be substituted with the java.lang.Void type.

The execution of an asynchronous task typically consists of the following steps:

1.execute (params ... params), performing an asynchronous task that requires us to call this method in code to trigger the execution of an asynchronous task.

2.onPreExecute (), executed immediately after the Execute (params ... params) is invoked, is typically used to mark the UI before performing a background task.

3.doInBackground (params ... params), executed immediately after OnPreExecute () is completed for a more time-consuming operation, this method receives the input parameters and returns the result of the calculation. You can call Publishprogress (Progress. Values) during execution to update the progress information.

4.onProgressUpdate (Progress. Values), when calling Publishprogress (Progress. Values), this method is executed to update the progress information directly to the UI component.

5.onPostExecute (result result), when the background operation ends, this method will be called, and the result will be passed as a parameter to this method, and the result will be displayed directly on the UI component.

In use, there are a few things that require extra attention:

1. An instance of an asynchronous task must be created in the UI thread.

The 2.execute (params ... params) method must be called in the UI thread.

3. Do not manually call OnPreExecute (), doinbackground (params ... params), onprogressupdate (Progress ... values), OnPostExecute ( Result result) of these several methods.

4. You cannot change the UI component information in the Doinbackground (params. params).

5. A task instance can only be executed once, and an exception will be thrown if the second execution occurs.


Package Com.scott.async;

Import Java.io.ByteArrayOutputStream;
Import Java.io.InputStream;

Import org.apache.http.HttpEntity;
Import Org.apache.http.HttpResponse;
Import Org.apache.http.HttpStatus;
Import org.apache.http.client.HttpClient;
Import Org.apache.http.client.methods.HttpGet;
Import org.apache.http.impl.client.DefaultHttpClient;

Import android.app.Activity;
Import Android.os.AsyncTask;
Import Android.os.Bundle;
Import Android.util.Log;
Import Android.view.View;
Import Android.widget.Button;
Import Android.widget.ProgressBar;
Import Android.widget.TextView;

public class Mainactivity extends Activity {

private static final String TAG = "Async_task";

Private Button Execute;
Private Button Cancel;
Private ProgressBar ProgressBar;
Private TextView TextView;

Private MyTask Mtask;

@Override
public void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.main);

Execute = (Button) Findviewbyid (R.id.execute);
Execute.setonclicklistener (New View.onclicklistener () {
@Override
public void OnClick (View v) {
Note the new task can only be executed once for each instance, or an exception will occur
Mtask = new MyTask ();
Mtask.execute ("http://www.baidu.com");

Execute.setenabled (FALSE);
Cancel.setenabled (TRUE);
}
});
Cancel = (Button) Findviewbyid (r.id.cancel);
Cancel.setonclicklistener (New View.onclicklistener () {
@Override
public void OnClick (View v) {
Cancels an executing task, the Oncancelled method will be called
Mtask.cancel (TRUE);
}
});
ProgressBar = (ProgressBar) Findviewbyid (R.id.progress_bar);
TextView = (TextView) Findviewbyid (R.id.text_view);

}

Private class MyTask extends Asynctask<string, Integer, string> {
The OnPreExecute method is used to do some UI action before performing a background task
@Override
protected void OnPreExecute () {
LOG.I (TAG, "OnPreExecute () called");
Textview.settext ("Loading ...");
}

The Doinbackground method performs background tasks internally and cannot modify the UI within this method
@Override
Protected string Doinbackground (String ... params) {
LOG.I (TAG, "doinbackground (params ... params) called");
try {
HttpClient client = new Defaulthttpclient ();
HttpGet get = new HttpGet (params[0]);
HttpResponse response = Client.execute (get);
if (Response.getstatusline (). Getstatuscode () = = HTTPSTATUS.SC_OK) {
httpentity entity = response.getentity ();
InputStream is = Entity.getcontent ();
Long total = Entity.getcontentlength ();
Bytearrayoutputstream BAOs = new Bytearrayoutputstream ();
byte[] buf = new byte[1024];
int count = 0;
int length =-1;
while (length = Is.read (BUF))! =-1) {
Baos.write (buf, 0, length);
Count + = length;
Call Publishprogress to announce the progress, and finally the Onprogressupdate method will be executed
Publishprogress ((int) ((Count/(float) total) * 100));
To demonstrate progress, hibernate 500 milliseconds
Thread.Sleep (500);
}
return new String (Baos.tobytearray (), "gb2312");
}
} catch (Exception e) {
LOG.E (TAG, E.getmessage ());
}
return null;
}

Onprogressupdate method for updating progress information
@Override
protected void Onprogressupdate (Integer ... progresses) {
LOG.I (TAG, "onprogressupdate (Progress ... progresses) called");
Progressbar.setprogress (Progresses[0]);
Textview.settext ("Loading ..." + progresses[0] + "%");
}

The OnPostExecute method is used to update the UI after performing a background task, displaying the results
@Override
protected void OnPostExecute (String result) {
LOG.I (TAG, "onpostexecute (result result) called");
Textview.settext (result);

Execute.setenabled (TRUE);
Cancel.setenabled (FALSE);
}

The Oncancelled method is used to change the UI when canceling a task in execution
@Override
protected void oncancelled () {
LOG.I (TAG, "oncancelled () called");
Textview.settext ("cancelled");
Progressbar.setprogress (0);

Execute.setenabled (TRUE);
Cancel.setenabled (FALSE);
}
}
}


The layout file Main.xml code is as follows:


<?xml version= "1.0" encoding= "Utf-8"?>
<linearlayout xmlns:android= "Http://schemas.android.com/apk/res/android"
android:orientation= "Vertical"
Android:layout_width= "Fill_parent"
android:layout_height= "Fill_parent" >
<button
Android:id= "@+id/execute"
Android:layout_width= "Fill_parent"
android:layout_height= "Wrap_content"
Android:text= "Execute"/>
<button
Android:id= "@+id/cancel"
Android:layout_width= "Fill_parent"
android:layout_height= "Wrap_content"
Android:enabled= "false"
android:text= "Cancel"/>
<progressbar
Android:id= "@+id/progress_bar"
Android:layout_width= "Fill_parent"
android:layout_height= "Wrap_content"
android:progress= "0"
android:max= "100"
Style= "? Android:attr/progressbarstylehorizontal"/>
<scrollview
Android:layout_width= "Fill_parent"
android:layout_height= "Wrap_content" >
<textview
Android:id= "@+id/text_view"
Android:layout_width= "Fill_parent"
android:layout_height= "Wrap_content"/>
</ScrollView>
</LinearLayout>


Because of the need to access the network, we also need to include access to the network in Androidmanifest.xml:

<uses-permission android:name= "Android.permission.INTERNET"/>

We can see how the key steps are in the way, doinbackground (params ... params) is an abstract method that we must override when we inherit Asynctask; OnPreExecute (), Onprogressupdate (Progress ... values), onpostexecute (result result), oncancelled () These methods are empty, and we can selectively overwrite them when we need them. The publishprogress (Progress ... values) is final modified, cannot be written, can only be called, and we generally call this method in the Doinbackground (params. params); We can see that there is a status enum class and a GetStatus () method, and the Status enumeration class code snippet is as follows:

Initial state
Private volatile Status mstatus = status.pending;

public enum Status {
/**
* Indicates that task have not been executed yet.
*/
PENDING,
/**
* Indicates the task is running.
*/
RUNNING,
/**
* indicates that {@link Asynctask#onpostexecute} have finished.
*/
Finished,
}

/**
* Returns The current status of this task.
*
* @return the current status.
*/
Public final Status GetStatus () {
return mstatus;
}


As you can see, the initial state of the Asynctask is pending, which represents the pending state, running represents the execution state, the finished represents the end state, and these states are used in many places in the Asynctask One life cycle, which is very important.

After we've covered the outline view, we'll start with the Execute (params ... params) as a portal and focus on the execution of the Asynctask, let's take a look at the code snippet for the Execute (params ... params) method:

Public final Asynctask<params, Progress, result> execute (params ... params) {
if (mstatus! = status.pending) {
Switch (mstatus) {
Case RUNNING:
Throws an exception if the task is being executed
It is worth mentioning that the state is still not running after calling Cancel to cancel the task
throw new IllegalStateException ("Cannot Execute task:"
+ "The task is already running.");
Case finished:
Throws an exception if the task has finished executing
throw new IllegalStateException ("Cannot Execute task:"
+ "The task has already been executed"
+ "(a task can be executed only once)");
}
}

Change status to Running
Mstatus = status.running;

Calling the OnPreExecute method
OnPreExecute ();

Mworker.mparams = params;
Sexecutor.execute (mfuture);

return this;
}


There are three unfamiliar variables involved in the code: Mworker, Sexecutor, Mfuture, and we'll look at them:

On Sexecutor, it is an instance of Java.util.concurrent.ThreadPoolExecutor that manages the execution of threads. The code is as follows:


private static final int core_pool_size = 5;
private static final int maximum_pool_size = 128;
private static final int keep_alive = 10;

Create a new queue to hold the thread
private static final blockingqueue<runnable> Sworkqueue =
New Linkedblockingqueue<runnable> (10);
Create a new thread factory
private static final Threadfactory sthreadfactory = new Threadfactory () {
Private final Atomicinteger MCount = new Atomicinteger (1);
Create a new thread
Public Thread Newthread (Runnable r) {
return new Thread (R, "Asynctask #" + mcount.getandincrement ());
}
};
Creates a new thread pool executor that manages the execution of threads
private static final Threadpoolexecutor Sexecutor = new Threadpoolexecutor (core_pool_size,
Maximum_pool_size, Keep_alive, Timeunit.seconds, Sworkqueue, sthreadfactory);

Mworker is actually an instance of the implementation object of an abstract inner class of Asynctask, which implements the call () method in the Callable<result> interface, with the following code:


private static abstract class Workerrunnable<params, Result> implements callable<result> {
Params[] Mparams;
}


While Mfuture is actually an example of java.util.concurrent.FutureTask, here is the information about its Futuretask class:

/**
* A cancellable asynchronous computation.
* ...
*/
public class Futuretask<v> implements runnablefuture<v> {

Public interface runnablefuture<v> extends Runnable, future<v> {
/**
* Sets this future to the result of its computation
* Unless it has been cancelled.
*/
void run ();
}


You can see that Futuretask is a class that can be canceled halfway for asynchronous computations.

The following are examples of mworker and mfuture that are reflected in the Asynctask:

Private final Workerrunnable<params, result> Mworker;
Private final futuretask<result> mfuture;

Public Asynctask () {
Mworker = new Workerrunnable<params, result> () {
After the call method is called, the priority is set to the background level, and then the Doinbackground method of the Asynctask is called
Public Result Call () throws Exception {
Process.setthreadpriority (Process.thread_priority_background);
Return Doinbackground (Mparams);
}
};

In the Mfuture instance, Mworker will be called to do the background task, and the done method will be called when finished
Mfuture = new Futuretask<result> (mworker) {
@Override
protected void done () {
Message message;
result = NULL;

try {
result = Get ();
} catch (Interruptedexception e) {
ANDROID.UTIL.LOG.W (Log_tag, E);
} catch (Executionexception e) {
throw new RuntimeException ("An error occured while executing doinbackground ()",
E.getcause ());
} catch (Cancellationexception e) {
Send a message to cancel a task
Message = Shandler.obtainmessage (Message_post_cancel,
New Asynctaskresult<result> (Asynctask.this, (result[]) null);
Message.sendtotarget ();
Return
} catch (Throwable t) {
throw new RuntimeException ("An error occured while executing"
+ "Doinbackground ()", t);
}

Send a message showing the result
Message = Shandler.obtainmessage (Message_post_result,
New Asynctaskresult<result> (Asynctask.this, Result));
Message.sendtotarget ();
}
};
}


We see in the code above that the Mfuture instance object's done () method sends a "MESSAGE_POST_CANCEL" message if it catches an exception of type cancellationexception, and if it executes successfully, it sends a " Message_post_result "message, and the message is associated with a Shandler object. This Shandler instance is actually an instance of the Asynctask inner class Internalhandler, and Internalhandler inherits handler, let's analyze its code:


private static final int message_post_result = 0x1;//display result
private static final int message_post_progress = 0x2;//Update Progress
private static final int message_post_cancel = 0x3;//Cancel Task

private static final Internalhandler Shandler = new Internalhandler ();

private static class Internalhandler extends Handler {
@SuppressWarnings ({"Unchecked", "Rawuseofparameterizedtype"})
@Override
public void Handlemessage (Message msg) {
Asynctaskresult result = (Asynctaskresult) msg.obj;
Switch (msg.what) {
Case Message_post_result:
There is only one result
Calling the Asynctask.finish method
Result.mTask.finish (Result.mdata[0]);
Break
Case Message_post_progress:
Calling the Asynctask.onprogressupdate method
Result.mTask.onProgressUpdate (Result.mdata);
Break
Case Message_post_cancel:
Calling the Asynctask.oncancelled method
Result.mTask.onCancelled ();
Break
}
}
}


We see that when we are dealing with a message, when we encounter "Message_post_result", it calls the finish () method in Asynctask, and we look at the definition of the finish () method:


private void finish (result result) {
if (iscancelled ()) result = NULL;
OnPostExecute (result);//Call OnPostExecute to display the result
Mstatus = status.finished;//Change status to Finished
}


The original finish () method is responsible for invoking the OnPostExecute (result result) method to display the result and change the state of the task.

In addition, in the Done () method of the Mfuture object, when building a message, the message contains an object of type Asynctaskresult, and then in the Handlemessage (Message msg) method of the Shandler instance object, Use the following method to get the object that is included in the message:


Asynctaskresult result = (Asynctaskresult) msg.obj;
What exactly is this asynctaskresult, and what does it contain? In fact, it is also an inner class of asynctask, a class used to package execution results, let's look at its code structure:

@SuppressWarnings ({"Rawuseofparameterizedtype"})
private Static Class Asynctaskresult<data> {
Final Asynctask Mtask;
Final data[] Mdata;

Asynctaskresult (asynctask task, data ... data) {
Mtask = task;
Mdata = data;
}
}

To see this asynctaskresult encapsulates a asynctask instance and some type of data set, let's look at the code when building the message:

Send a message to cancel a task
Message = Shandler.obtainmessage (Message_post_cancel,
New Asynctaskresult<result> (Asynctask.this, (result[]) null);
Message.sendtotarget ();


Send a message showing the result
Message = Shandler.obtainmessage (Message_post_result,
New Asynctaskresult<result> (Asynctask.this, Result));
Message.sendtotarget ();


How to use this object when handling messages, let's look at:


Result.mTask.finish (Result.mdata[0]);

Result.mTask.onProgressUpdate (Result.mdata);

In summary, when we call the Execute (params) params method, the Execute method calls the OnPreExecute () method, A futuretask task is then performed by the Threadpoolexecutor instance Sexecutor, during which the doinbackground (params) params is called, If the publishprogress (Progress ... values) method is called in the Doinbackground (params. Params) method that is written by the developer, Send a message_post_progress message through the Internalhandler instance Shandler, update the progress, Shandler process the message onprogressupdate (Progress ... values) The method is called, if an exception is encountered, a MESSAGE_POST_CANCEL message is sent, the task is canceled, the oncancelled () method is called when Shandler processes the message, and if the execution succeeds, a message_post_ is sent. The result of the message that displays the results, Shandler processing the message when the OnPostExecute (result result) method is called.

After the above introduction, I believe that friends have already recognized the essence of asynctask, it thread+handler good package, reduce the complexity of the developers to deal with the problem, improve the development efficiency, I hope friends can have a lot of experience.

Android Asynctask Detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.