Android UI operations are thread insecure, and if you want to perform UI operations on a Cheng Hong, you need to use Android-provided handler. The asynctask provided by Android is actually a handler package that allows us to update UI elements in a child thread. Asynctask is a generic class, written in the following format: Asynctask<params, Progress, result>. The purpose of these three parameters is as follows:
1. Params
The purpose of these three parameters is as follows:
1. Params
Parameters that need to be passed in when executing asynctask can be used in a background task.
2. Progress
When a background task executes, the generic type specified here is used as the progress unit if you need to display the current progress on the interface.
3. Result
When the task finishes executing, if the result needs to be returned, the generic type specified here is used as the return value type.
An asynctask usage given in the Android SDK is as follows:
Private class Downloadfilestask extends Asynctask (URL, Integer, long) { protected long doinbackground (URL ... urls) { C1/>int count = urls.length; Long totalsize = 0; for (int i = 0; i < count; i++) { totalsize + = Downloader.downloadfile (Urls[i]); Publishprogress ((int) ((I/(float) count)) ; Escape early if Cancel () is called if (iscancelled ()) break; } return totalsize; } protected void Onprogressupdate (Integer ... progress) { setprogresspercent (progress[0]); } protected void OnPostExecute (Long result) { showDialog ("downloaded" + result + "bytes"); } } New Downloadfilestask (). Execute (URL1, URL2, URL3);
Asynctask is an abstract class, and there are four methods that need to be rewritten, and the invocation of these four methods is as follows:
1th step. The OnPreExecute () method is called between the background task start execution and is used for initialization on some interfaces.
2nd step. Doinbackground (Params ...) All the code in the method will run in the sub-thread, and we should be here to handle all the time-consuming tasks. Once the task is complete, it can return the result of the task by using the return statement. If you need to update UI elements, such as feedback on the execution progress of the current task, you can call Publishprogress (Progress ...). method to complete.
3rd step. When Publishprogress (Progress ...) is called in a background task Method, Onprogressupdate (Progress ...) Methods are called quickly, 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.
4th step. When the background task is completed and returned by a return statement, OnPostExecute (Result) is called shortly. Here you can
for UI operations.
Source Code of Asynctask
When I used Asynctask, I didn't understand why Onprocessupdate was called regularly. Later in the work to achieve a scheduled Update task progress function, we use a handler to send themselves a message to do a timed refresh. Now we have studied the implementation principle of asynctask, and found that it also uses handler to send itself the principle of sending messages to achieve timed refresh. When I choose the source of Android 4.4, if you can understand the principle of asynctask, you can write a simple asynctask.
First look at the constructor: note that the constructor must be called in the UI.
/** * Creates a new asynchronous task. This constructor must is invoked on the UI thread. */Public Asynctask () {mworker = new workerrunnable<params, result> () {public Result call () t Hrows 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 (Cancellationexceptione) {postresultifnotinvoked (null); } } }; }This function first initializes two variables: Mworker and Mfuture. Mworker is a callable object, Mfuture is an object that implements Runnable and future. Execute (Params) is invoked to start Asynctask
Public final Asynctask<params, Progress, result> execute (params ... params) { return Executeonexecutor ( Sdefaultexecutor, params); }
The method calls the Executeonexecutor () method with the following code:
public final Asynctask<params, Progress, result> executeonexecutor (Executor exec, params ... params) {if (mstat us! = status.pending) {switch (mstatus) {case Running:throw new Illegalsta Teexception ("Cannot execute task:" + "The task is already running."); Case Finished:throw New IllegalStateException ("Cannot execute task:" + "th E task has already been executed "+" (a task can is executed only once) "); }} mstatus = status.running; OnPreExecute (); Mworker.mparams = params; Exec.execute (mfuture); return this; }
The method first sets the run state, then calls OnPreExecute, and finally calls Exec.execute (Mfuture). The incoming exec is sdefaultexecutor, Sdefaultexecutor is a Serialexecutor object with the following source code:
private static class Serialexecutor implements Executor { final arraydeque<runnable> mtasks = new Arraydeque< ; Runnable> (); Runnable mactive; Public synchronized void Execute (final Runnable R) { Mtasks.offer (new Runnable () {public void run () { try {
r.run (); } finally { schedulenext ();}} ); if (mactive = = null) { schedulenext (); } } protected synchronized void Schedulenext () { if ((mactive = Mtasks.poll ())! = null) { Thread_pool_ Executor.execute (mactive);}}}
When calling Sdefaultexecutor.execute (runnable), the method uses a arraydeque to save the runnable,runnable and is called at the appropriate time. The first run of mactivity equals null, and the Schedulenext () method is called. In this method, a value is taken from the head of the queue, assigned to the Mactive object, and then called Thread_pool_executor to execute the extracted runnable object. A try finally block is used here, and the Schedulenext () method is called in Finally, and each time a task executes, the next task is executed, and serialexecutor mimics the effect of a single thread pool. If we start a lot of tasks quickly, only one thread is executing at the same time, and the rest is waiting.
Sdefaultexecutor.execute (Runnable) The object that is passed in is Mfuture,mfuture is a Futuretask object whose constructor is as follows:
Public Futuretask (callable<v> callable) { if (callable = = null) throw new NullPointerException (); this.callable = callable; This.state = NEW; Ensure visibility of callable }
The Asynctask constructor shows that the callable in Futuretask is the Mworkder object. The run () code for Futuretask is as follows:
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); } }Therefore, the call () of Mworker is eventually called. Mworker's Call () is located in the constructor of Asynctask, and you can find its first calls Doinbackgroud (Params) and then calls Postresult (). The source code for Postresult (Result) is as follows:
Private result Postresult (result result) { @SuppressWarnings ("unchecked") message message = Shandler.obtainmessage (Message_post_result, new asynctaskresult<result> (this, RESULT)); Message.sendtotarget (); return result; }
Shandler is a internalhandler, the code 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;}}}
When a message_post_result message is passed in, the Asynctask.finish () method is executed, and if this is a message_post_progress message, the Onprogressupdate () method is executed. When we use the For loop in Doinbackgroud (Params) to invoke publishprogress (Progress ... values), we simulate
The effect of calling onprogressupdate (Progress ... values) on a timed basis. The source code for publishprogress (Progress ... values) is as follows:
Protected final void publishprogress (Progress ... values) { if (!iscancelled ()) { Shandler.obtainmessage ( Message_post_progress, New asynctaskresult<progress> (this, values)). Sendtotarget (); } }
It first determines if the thread has ended, and if it does not, Shandler sends itself a message with the type message_post_progress,shandler.handlemessage (message) The Onprogressupdate (Progress ... values) is called.
The Sdefaultexecutor first calls Mfuture's run (), and Mfuture's Run () calls Mworker's call (). When a task is completed, Mfuture's done () is called back. Done () will call ppostresultifnotinvoked (result result), the source code is as follows:
private void postresultifnotinvoked (result result) { final Boolean wastaskinvoked = Mtaskinvoked.get (); if (!wastaskinvoked) { postresult (result); } }
Postresult (Result) has already been explained in the preceding, no longer repeat here.