The Asynctask principle of Android

Source: Internet
Author: User

As you can tell by name, Asynctask is primarily used to handle asynchronous tasks in Android. But through the source code, we can see that its implementation is still dependent on the handler asynchronous message processing mechanism. Now let's learn how to use it and then study the source code.

A Basic usage of Asynctask:

Asynctask is an abstract class that, when inheriting it, must specify three generic parameters, and the three parameters are used as follows:
1. Parameters that need to be passed in when executing asynctask can be used in a background task.
2. When any execution occurs in the background, if you need to display the current progress on the interface, use the generic type specified here as the progress unit. 3. When the task finishes executing, if you need to return the result, use the generic type specified here as the return value type.
Custom Asynctask such as the following example:

public class Downasynctask extends Asynctask<string, Integer, byte[]>

Here we specify the first generic parameter of Asynctask as a string, which means that the string parameter needs to be passed to the background task when the Asynctask is executed. The second generic parameter is specified as Integer, which indicates that the integer data is used as the progress display unit. The third generic parameter is specified as byte[], which means that a byte array is used to feedback the execution result.

Of course, our custom downasynctask is still an empty task and cannot do any actual work, and we need to rewrite several methods in the Asynctask to complete the customization of the task. There are four ways to rewrite the following frequently:

    OnPreExecute ()

This method is called between the start of the background task and is used for initialization on some interfaces, such as displaying a progress bar dialog box, and so on.

    Doinbackground (Params ...)

All the code in this method will run in a sub-thread, and we should be here to handle all the time-consuming tasks. Once the task is completed, the execution result of the task can be returned by the return statement, and if Asynctask's third generic parameter specifies void, the task execution result is not returned. Note that the UI action is not allowed in this method, and if you need to update the UI elements, such as feedback on the progress of the current task, you can call Publishprogress (Progress ...). method to complete.
    Onprogressupdate (Progress ...)

When Publishprogress (Progress ...) is called in a background task Method, the method is quickly called, and the parameters that are carried in the method are passed in the background task. The UI can be manipulated in this method, and the interface elements can be updated accordingly using the values in the parameters.
    OnPostExecute (Result)

This method is called quickly when the background task is completed and returned through a return statement. The returned data is passed as a parameter to this method, and the returned data can be used to perform some UI actions, such as reminding the result of the task execution, and closing the Progress Bar dialog box.

As a result, a more complete custom asynctask can be written in the following ways:

public class Downasynctask extends Asynctask<string, Integer, byte[]>{private String TAG = "Downasynctask";p rivate ProgressDialog mprogress;private Context mcontext;private ImageView imagebutton;public downasynctask (Context MContext , ImageView ImageButton) {this.mcontext = Mcontext;this.imagebutton = ImageButton;} @Overrideprotected byte[] Doinbackground (String ... params) {//TODO auto-generated method STUBANDROID.UTIL.LOG.V (TAG, "        Downasynctask--------Doinbackground ");        Access a picture in the request network via Apache's HttpClient HttpClient HttpClient = new Defaulthttpclient ();        HttpGet httpget = new HttpGet (params[0]);        byte[] image = new byte[]{};            try {HttpResponse HttpResponse = Httpclient.execute (HttpGet);            Httpentity httpentity = httpresponse.getentity ();                if (httpentity! = null && httpresponse.getstatusline (). Getstatuscode () = = HTTPSTATUS.SC_OK) {      Image = Entityutils.tobytearray (httpentity);      }            //.. Depending on the download, use Publishprogress () to notify Onprogressupdate () to update the progress bar} catch (Exception e) {e.printstackt        Race ();        } finally {Httpclient.getconnectionmanager (). Shutdown (); } return image; @Overrideprotected void OnPreExecute () {//TODO auto-generated method STUBANDROID.UTIL.LOG.V (TAG, " Downasynctask--------OnPreExecute ");//Set and display the progress bar mprogress = new ProgressDialog (mcontext); Mprogress.settitle (" Xiazai "); Mprogress.setmessage (" Download is running "); Mprogress.setprogressstyle (Progressdialog.style_spinner); Mprogress.show (); Super.onpreexecute ();} @Overrideprotected void OnPostExecute (byte[] result) {//TODO auto-generated method stub//After the end of the asynchronous download, replace the control picture, Close the progress bar android.util.log.v (TAG, "Downasynctask--------OnPostExecute:" +result.length+ "path:" +path); Bitmap Mbitmap = Bitmapfactory.decodebytearray (result, 0, result.length); Imagebutton.setimagebitmap (MBITMAP); Mprogress.dismiss (); Super.onpostexecute (result);} @Overrideprotected void Onprogressupdate (Integer ... values) {//TODO auto-generated method STUBANDROID.UTIL.LOG.V (TAG, " Downasynctask--------onprogressupdate "); Super.onprogressupdate (values);} @Overrideprotected void oncancelled (byte[] result) {//TODO auto-generated method STUBANDROID.UTIL.LOG.V (TAG, " Downasynctask--------oncancelled "); super.oncancelled (result);} @Overrideprotected void oncancelled () {//TODO auto-generated method STUBANDROID.UTIL.LOG.V (TAG, " Downasynctask--------oncancelled "); super.oncancelled ();}}

The Asynctask sub-class is defined, and the Asynctask task is opened as follows:

public class Mainactivity extends Activity {private Button downbutton;private ImageView mpictrue;private String uripath = "Http://ww2.sinaimg.cn/mw690/69c7e018jw1e6hd0vm3pej20fa0a674c.jpg"; @Overrideprotected void OnCreate (Bundle Savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_main);d Ownbutton = ( Button) Findviewbyid (R.id.button), mpictrue = (ImageView) Findviewbyid (r.id.image);d Ownbutton.setonclicklistener ( New Onclicklistener () {@Overridepublic void OnClick (View v) {//TODO auto-generated method Stubdownasynctask dat = new Dow Nasynctask (mainactivity.this,mpictrue);d At.execute (Uripath);}});}}

above is the basic use of asynctask, we do not need to consider what asynchronous message processing mechanism, and do not have to use a special handler to send and receive messages, Just calling the Publishprogress () method makes it easy to switch from a child thread to a UI thread.
Of course, we can also cancel the execution of our asynchronous task at any moment, by calling the Cancel method, which then calls the IsCancelled () method and returns True. If this method is called, then the OnPostExecute () method is not called after the Doinbackgroud () method is executed, instead of calling the Oncancelled () method. To ensure that the task has been canceled, we need to call the IsCancelled () method frequently to determine if necessary.



   from the Downasynctask, we can see that we must first create a new Downasynctask object, Then call the Execute () method to start the task. Before new Downasynctask (), you have to implement the constructor of its parent class Asynctask, as follows:

Public Asynctask () {mworker = new workerrunnable<params, result> () {public Result call () throws                Exception {Mtaskinvoked.set (true);                Process.setthreadpriority (Process.thread_priority_background);            Noinspection unchecked return Postresult (Doinbackground (mparams));        }        }; Mfuture = new Futuretask<result> (mworker) {@Override protected void done () {T                ry {postresultifnotinvoked (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) {postresultifnotinvoked (null); }            }        };}

This Asynctask constructor method only initializes two variables, Mworker and mfuture. When initializing the mfuture, Mworker is passed as a parameter, and here we leave it in the first place. After initialization is complete, if you want to start a task, you must call the Execute () method, as follows:

Public final Asynctask<params, Progress, result> execute (params ... params) {return Executeonexecutor (sdefaul    Texecutor, params); Public final Asynctask<params, Progress, result> executeonexecutor (Executor exec, params ... params) {if (mstatus! = status.pending) {switch (mstatus) {case running:th                Row new IllegalStateException ("Cannot execute task:" + "The task is already running.");                            Case Finished:throw New IllegalStateException ("Cannot Execute task:"            + "The task has already been executed" + "(a task can is executed only once)");        }} mstatus = status.running;        OnPreExecute ();        Mworker.mparams = params;        Exec.execute (mfuture);    return this; }

Here, you can see that OnPreExecute is executed before other methods such as Doinbackground (), and there is no other thread in the process, so this is also the scope of execution for the UI thread. This method is primarily used to initialize other initialization tasks such as controls for some UI interfaces. The next execution of Exec.execute (mfuture), exec is the previously passed Sdefaultexecutor, and execute (mfuture) The method then passes the mfuture as a formal parameter into the Serialexecutor execute, and encapsulates the mfuture related operation in a different thread, as follows:

public Static final Executor serial_executor = new Serialexecutor ();p rivate static volatile Executor Sdefaultexecutor = serial_ex    Ecutor; private static class Serialexecutor implements Executor {final arraydeque<runnable> mtasks = new arraydeque& Lt        Runnable> ();        Runnable mactive; Public synchronized void Execute (final Runnable R) {Mtasks.offer (new Runnable () {public void R                    Un () {try {r.run ();                    } finally {Schedulenext ();            }                }            });            if (mactive = = null) {Schedulenext ();                }} protected synchronized void Schedulenext () {if ((mactive = Mtasks.poll ()) = null) {            Thread_pool_executor.execute (mactive); }        }    }

As you can see, Exec.execute (mfuture) executes the Execute () method in the Serialexecutor class. Serialexecutor the role of this class is somewhat like a queue manager, which maintains a arraydeque queue to hold runnable objects and manages them (FIFO). For example: If I want to download hundreds of images asynchronously, I need to execute hundreds of execute () methods to start the task. In this way, each downloaded task is added to the Arraydeque queue and is processed sequentially as it enters. (With regard to Thread_pool_executor.execute (mactive) The implementation of this, is not very clear).
In Serialexecutor's execute () method, executed the R.run (), well, here a thread is going to start, and the asynchronous process starts. Since the incoming is mfuture, after the queue starts processing, the code runs into the Asynctask constructor method and looks at the Futuretask class:

Public Futuretask (callable<v> callable) {        if (callable = = null)            throw new NullPointerException ();        this.callable = callable;        This.state = NEW;       Ensure visibility of callable    }

See what this callable is? It was mworker, and when the Futuretask object was constructed Mworker was passed in as a formal parameter. Continue to see the Futuretask class of the Run method:

public void Run () {if ' state! = NEW | | !            Unsafe.compareandswapobject (this, runneroffset, NULL, Thread.CurrentThread ()))        Return            try {callable<v> c = callable;                if (c! = null && state = = NEW) {V result;                Boolean ran;                    try {result = C.call ();                ran = true;                    } catch (Throwable ex) {result = null;                    ran = false;                SetException (ex);            } if (ran) set (result); }} finally {//runner must be non-null until state is settled to//prevent concurrent call            s to run () runner = null;            State must is re-read after nulling runner to prevent//leaked interrupts int s = State;    if (s >= interrupting)            Handlepossiblecancellationinterrupt (s); }    }

Callable is mworker, then this result = C.call (); execution is definitely the call () method in the Workerrunnable class, OK, back to the Asynctask construction method, see, there is no familiar place: return Postresult (Doinbackground (mparams)); finally see the Doinbackground method executed. Starting with Serialexecutor's execute (), another thread is started, so this doinbackground () entire method runs in a new thread, so all time-consuming operations should be performed in the Doinbackground () method.
All right, keep going.

Private result Postresult (result result) {        @SuppressWarnings ("unchecked")        message message = Shandler.obtainmessage (Message_post_result,                new asynctaskresult<result> (this, RESULT));        Message.sendtotarget ();        return result;}

Here, a message is sent with the Shandler object that carries the Message_post_result constant and a Asynctaskresult object that represents the result of the task execution. This Shandler object is an instance of the Internalhandler class, and later this message will certainly be handled in the Internalhandler handlemessage () method. The source code for Internalhandler is as follows:

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 are only one RESULT                    result.mTask.finish ( Result.mdata[0]);                    break;                Case message_post_progress:                    result.mTask.onProgressUpdate (result.mdata);                    Break;}}}        

The type of the message is judged, and if this is a message_post_result message, it executes the finish () method, and if this is a message_post_progress message, it executes onprogressupdate ( Method Then the source code for the finish () method is as follows:
private void finish (result result) {        if (iscancelled ()) {            oncancelled (result);        } else {            OnPostExecute ( result);        }        Mstatus = status.finished;    }

As you can see, if the current task is canceled, the oncancelled () method is called, and if it is not canceled, the OnPostExecute () method is called, so that the execution of the current task is all over.
So, there is a message_post_progress in the Internalhandler just now: message, when did it send a message notice?

Protected final void publishprogress (Progress ... values) {        if (!iscancelled ()) {            Shandler.obtainmessage ( Message_post_progress,                    New asynctaskresult<progress> (this, values)). Sendtotarget ();        }}

Therefore, to update the progress bar of a task, the Publishprogress () method is required to send a message notification, and Internalhandler receives a message notification before the onprogressupdate () is executed for a progress bar update.
These are some of the principles of asynctask analysis. In fact, the asynchronous processing mechanism of Android, essentially only through the handler to achieve, Asynctask just a good package for it, let us use more convenient.

Reference Link: http://blog.csdn.net/guolin_blog/article/details/11711405




The Asynctask principle of Android

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.