Specifically explains the use of Asynctask in Android

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, the interface is updated, so that the overall control of the process is more granular, but also has shortcomings, such as the relatively bloated code, when multiple tasks run at the same time, Precise control of the thread is not easy. About handler knowledge, the front also has introduced, unclear friends can take a look.

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 complete the same task.

First look at the definition of Asynctask:

Public abstract class Asynctask<params, Progress, result> {

Three generic types represent the input parameters run by startup task, the progress of background task runs, and the type of background calculation results, respectively. In certain situations, not all types are used, assuming they are not used and can be substituted with the java.lang.Void type.

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

1.Execute (params ... params), run an asynchronous task that requires us to call this method in code to trigger the operation of an asynchronous task.

2.onpreexecute ()runs immediately after the Execute (params ... params) is invoked, and is typically used to mark the UI before running a background task.

3.Doinbackground (params. Params), run immediately after OnPreExecute () to run a more time-consuming operation, this method will receive input parameters and return the results of the calculation. You can call Publishprogress (Progress. Values) during the run to update the progress information.

4.onprogressupdate (Progress. Values), when calling publishprogress (Progress ... values), this method is run and updates 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 to this method as a parameter, directly displaying the result on the UI component.

In use, there are several points that need to be paid extra attention to:

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 run once, assuming that the second time it runs will throw an exception.

Next, let's take a look at how to run an asynchronous task operation using Asynctask, we first build a project with a structure such as the following:

The structure is relatively simple, let's take a look at Mainactivity.java's code first:

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";p rivate button execute;private button cancel;private ProgressBar progressbar;private Text View 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 () {@Overridepublic void OnClick (View v) {//Note each time a new instance is required, the newly created task can only run once, Otherwise there will be an exception 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 () {@Overridepublic void OnClick (View v) {//cancels a running 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> {//onpreexecute method is used to do some UI action before running a background task @ Override protected void OnPreExecute () {log.i (TAG, "OnPreExecute () called"); Textview.settext ("Loading ..."); The//doinbackground method runs the background task internally, and you cannot change ui@overrideprotected string Doinbackground (String ... params) within this method {log.i (TAG, "DoI Nbackground (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 publish Progress, The last Onprogressupdate method will be run publishprogress ((int) ((Count/(float) total) * 100);//To demonstrate progress, hibernate 500 Ms Thread.Sleep (500);} return new String (Baos.tobytearray (), "gb2312");}} catch (Exception e) {log.e (TAG, E.getmessage ());} return null;} The Onprogressupdate method is used to update the progress information @override protected void onprogressupdate (Integer ... progresses) {log.i (TAG, " Onprogressupdate (Progress ... progresses) called ");p rogressbar.setprogress (Progresses[0]); Textview.settext (" Loading "+ progresses[0] +"% "); } The OnPostExecute method is used to update the UI after running the background task, showing the result @overrideprotected 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 ui@overrideprotected void oncancelled () {log.i (TAG, "oncancelled () called") when canceling a running task; Textview.settext ("cancelled");p rogressbar.setprogress (0); execute.setenabled (true); cancel.setenabled (false);} }}

The

Layout file Main.xml code such as the following:

<?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" a Ndroid:text= "Execute"/> <button android:id= "@+id/cancel" android:layout_width= "Fill_parent" Android:layo ut_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= "style="? Android:attr/progressbarstylehorizontal "/><scrollviewandroid:layout_width=" fill _parent "android:layout_height=" wrap_content "><textviewandroid:id=" @+id/text_view "android:layout_width=" Fill_parent "android:layout_height=" wrap_content "/></ScrollView></LinearLayout>

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

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

Let's take a look at the execution interface:

Each of the above is the initial interface, the interface to run the asynchronous task, the post-successful interface, and the post-cancellation interface. After a successful run, the entire process log prints such as the following:

Suppose we press the "Cancel" button while running the task, the log prints such as the following:

You can see that the oncancelled () method will be called, and the OnPostExecute (result result) method will no longer be called.

The above describes the basic application of asynctask, some friends may have doubts, asynctask inside is how to run, it runs the process with us use handler what difference? The answer is: Asynctask is a good package for Thread+handler, and the trace of thread and handler can still be seen in Android.os.AsyncTask code. The following is a detailed introduction to the operation Principle of asynctask.

Let's take a look at Asynctask's outline view:

The way we can see the key steps is that the 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, not writable, can only be called, and we usually call this method in the Doinbackground (params. params); We can see that there is a status enum class and a GetStatus () method, the Status enumeration class code snippet such as the following:

//Initial state private volatile status Mstatus = Status.pending;public enum Status {/** * indicates tha T the task has a 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; }

It is important to see that the initial state of Asynctask is pending, represents the pending state, running represents the running state, and the finished represents the end state, which is used in a very many places in the Asynctask life cycle.

After we've covered the outline view, we'll start with the Execute (params ... params) as an entry point, and we'll focus on the asynctask flow, and we'll look at the code snippet for the Execute (params ... params) method:

Public final Asynctask<params, Progress, result> execute (params ... params) {if (Mstatus! = Status.pendin G) {switch (mstatus) {case running://if the task is being run throws an exception//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 run Ning. "); Case FINISHED://assumes that the task has finished running and throws an exception throw new IllegalStateException ("Cannot Execute task:" + "The task has already been executed" + "(a task can is executed only once)"); }}//change state to RUNNING mstatus = status.running;//Call 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:

With regard to Sexecutor, it is an instance of Java.util.concurrent.ThreadPoolExecutor for managing the running 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 on the public thread Newth Read (Runnable R) {return new Thread (R, "Asynctask #" + mcount.getandincrement ()); }};//creates a new thread pool runner for managing threads running 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, such as 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& Gt {

Public Interface Runnablefuture<v> extends Runnable, future<v> {/** * sets this future to the ResU LT's 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 is the embodiment of the Mworker and Mfuture instances in Asynctask:

Private final Workerrunnable<params, result> Mworker; Private final futuretask<result> mfuture;public Asynctask () {mworker = new workerrunnable<params, Result& gt; () {//call method is called, the priority is set to the background level, and then the Doinbackground method of Asynctask is called Public Result call () throws Exception { Process.setthreadpriority (Process.thread_priority_background); Return Doinbackground (Mparams); };//in the Mfuture instance, the Mworker will be called to do the background task, and the done method will be called after completion 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 doinbackg Round () ", E.getcause ()); } catch (Cancellationexception e) {//Send Cancel 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); }//sends the message that displays the result. Shandler.obtainmessage (Message_post_result, New Asynctaskresu Lt<result> (Asynctask.this, Result)); Message.sendtotarget (); } }; }

  We see in the above code, the Mfuture instance object's done () method, assuming that an exception of type cancellationexception is caught, a message "Message_post_cancel" is sent ; If run smoothly, a "message_post_result" message is sent, 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, so 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 Interna Lhandler ();p rivate static class Internalhandler extends Handler {@SuppressWarnings ({"Unchecked", "rawuseofparamete Rizedtype "}) @Override public void Handlemessage (Message msg) {asynctaskresult result = (asyncta Skresult) Msg.obj; Switch (msg.what) {case Message_post_result://There are only one result//call Asynctask.f Inish method Result.mTask.finish (result.mdata[0]); Break Case message_post_progress://Call Asynctask.onprogressupdate method Result.mTask.onProgressUpdate (Result.mdata) ; Break Case message_post_cancel://calls 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 display 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 includes an object of type Asynctaskresult, and then in the Handlemessage (Message msg) method of the Shandler instance object, Use the following methods to get the objects that are included in the message:

asynctaskresult result = (Asynctaskresult) msg.obj;

What exactly is this asynctaskresult, and what does it include? In fact it is also an inner class of asynctask, a class used to wrap the results of a run, let's look at its code structure:

@SuppressWarnings ({"Rawuseofparameterizedtype"}) private static class Asynctaskresult<data> {FINA L 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 message to cancel task msg = Shandler.obtainmessage (Message_post_cancel, New asynctaskresult<result> (asynctask.t His, (result[]) null); Message.sendtotarget ();

//Send message with display result = Shandler.obtainmessage (Message_post_result, New asynctaskresult<result> (asynctask.t his, 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 run by the Threadpoolexecutor instance Sexecutor, during which the doinbackground (params) params is called, Assume that the publishprogress (Progress ... values) method is called in the Doinbackground (params. Params) method that is being 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, assuming an exception is encountered, sending a message_post_cancel message, canceling the task, Shandler processing the message when the Oncancelled () method is invoked, and assuming a successful run, sending a message_post_ 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 is good package for thread+handler, reduce the complexity of the developers to deal with the problem, improve the development efficiency, I hope friends can have a lot of experience.

Specifically explains the use of Asynctask in Android

Related Article

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.