Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to parse the android asynchronous message mechanism from the source code level

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article shows you how to parse the android asynchronous message mechanism from the source code level, the content is concise and easy to understand, can definitely brighten your eyes, through the detailed introduction of this article, I hope you can get something.

AsyncTask

What is AsyncTask?

AsyncTask is a lightweight asynchronous task class that executes background tasks in a thread pool, then passes the progress and results of execution to the main thread and updates the UI in the main thread.

The declaration of the class AsyncTask is as follows

Public abstract class AsyncTask

It provides three generic parameters, Params, Progress and Result. The specific meaning of these three generic parameters will be analyzed in detail below.

AsyncTask provides four core methods

OnPreExecute ()

This method, which is executed in the main thread, is called before the asynchronous task is executed, and is generally used for preparatory work, such as initializing the download progress bar.

DoInBackground (Params... Params)

This method is executed in a child thread and is used to perform asynchronous tasks. Note that params here is the first parameter type of AsyncTask. In this method, you can update the progress of the task by calling the publicProgress method, and publicProgress calls the onProgressUpdate method.

OnProgressUpdate (Progress... Values)

This method is executed in the main thread, and the type of values is the second parameter type passed in by AsyncTask, which executes when the execution progress of the background task changes.

OnPostExecute (Result result)

This method is executed in the main thread and is called after the execution of the doInBackground method is completed, where the type of result is the third parameter type passed in by AsyncTask, and its value is the return value of the doInBackground method.

Then take a look at the most common use of AsyncTask, this example is to download a picture to the phone's memory cache directory, the start of the download will pop up the progress box, in the download process shows the progress of the download, after the download is completed, close the progress box, if successful, there will be a successful download Toast, failure will pop up the failed Toast.

Class MyAsyncTask extends AsyncTask {@ Overrideprotected void onPreExecute () {progressDialog = new ProgressDialog (MainActivity.this); progressDialog.setTitle (download Progress); progressDialog.setMax; progressDialog.setProgressStyle (ProgressDialog.STYLE_HORIZONTAL); progressDialog.setCancelable (true); progressDialog.show ();} @ Overrideprotected Boolean doInBackground (Void...) Params) {HttpURLConnection conn = null; try {conn = (HttpURLConnection) params [0] .openConnection (); conn.setRequestMethod ("GET"); conn.setConnectTimeout (5000); conn.setReadTimeout (5000); final int contentLength; if (conn.getResponseCode () = 200) {contentLength = conn.getContentLength (); File file = new File (getCacheDir (), "hh.jpg"); InputStream is= null; FileOutputStream fos= new FileOutputStream (file); is= conn.getInputStream (); int len = 0; long totalSize = 0; byte [] bytes = new byte [0] While ((len = is.read (bytes))! =-1) {fos.write (bytes,0,len); totalSize + = len*100; int progress = (int) (totalSize/contentLength); publishProgress (progress);} catch (IOException e) {e.printStackTrace ();} return true;} @ Override protected void onProgressUpdate (Integer...) Values) {progressDialog.setProgress (values [0]);} @ Override protected void onPostExecute (Boolean aBoolean) {progressDialog.dismiss (); if (result) {Toast.makeText (context, "download successful", Toast.LENGTH_SHORT). Show ();} else {Toast.makeText (context, "download failed", Toast.LENGTH_SHORT). Show ();}

This class is mainly used to simulate the download process of files. The input parameter is the image url address, the background process parameter is Integer type, and the return result of background task is bollean type. When you want to perform the above download task, you can do it in the following ways:

/ / when called in the main thread, methods such as doInBackground such as URL url = new URL ("http://192.168.43.21:8080/ditu.jpg"); new MyAsyncTask () .execute (url)) are executed.

Source code analysis

First of all, we start with the construction method of AsyncTask.

/ * Creates a new asynchronous task. This constructor must be invoked on the UI thread. * / public AsyncTask () {mWorker = new WorkerRunnable () {public Result call () throws Exception {mTaskInvoked.set (true); Process.setThreadPriority (Process.THREAD_PRIORITY_BACKGROUND); / / noinspection unchecked Result result = doInBackground (mParams); Binder.flushPendingCommands (); return postResult (result);}}; mFuture = new FutureTask (mWorker) {@ Override protected void done () {try {postResultIfNotInvoked (get ());} catch (InterruptedException e) {android.util.Log.w (LOG_TAG, e) } catch (ExecutionException e) {throw new RuntimeException ("An error occurred while executing doInBackground ()", e.getCause ());} catch (CancellationException e) {postResultIfNotInvoked (null);};}

1. As the comment says, this constructor must be called in the UI thread. two。 The constructor mainly creates two instances. One is WorkerRunnable, which is a Callback object. The other is FutureTask, whose parameter is the WorkerRunnable object you created earlier.

Next, let's take a look at AsyncTask's execute () method, which is the entrance to the entire asynchronous task.

@ MainThread public final AsyncTask execute (Params... Params) {return executeOnExecutor (sDefaultExecutor, params);} @ MainThread public final AsyncTask executeOnExecutor (Executor exec, Params...) Params) {if (mStatus! = Status.PENDING) {switch (mStatus) {case RUNNING: throw 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 be executed only once)");} mStatus = Status.RUNNING; / / onPreExecute () call onPreExecute () / / the parameter here is passed into doInBackground (mParams) by the first parameter passed in the AsyncTask constructor, mWorker.mParams = params; / / * exec.execute (mFuture); return this;}

We see that onPreExecute () is called, proving that it is indeed called before the background task is executed, and that it is called in the main thread. At this point, we perform the display operation of the progress bar display box in the example code, and the interface is as follows

There is also an operation exec.execute (mFuture) in this method. First of all, we need to know what exec is. We can get the answer in the following source code.

Public static final Executor SERIAL_EXECUTOR = new SerialExecutor (); private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR

According to the above code and the parameters passed in by executeOnExecutor, we can see that the exec here is actually SerialExecutor, so let's take a look at the execute method of SerialExecutor

Public synchronized void execute (final Runnable r) {mTasks.offer (new Runnable () {public void run () {try {r.run ();} finally {scheduleNext ();}); if (mActive = = null) {scheduleNext ();}}

We see that r.run () is executed in the child thread. According to the parameters passed in the execute () method, we can see that the r here is the FutureTask originally created in the constructor. Of course, it's time to take a look at the run () method of FutureTask.

Public void run () {if (state! = NEW | |! U.compareAndSwapObject (this, RUNNER, null, Thread.currentThread ()) return; try {Callable 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 calls to run () runner = null; / / state must be re-read after nulling runner to prevent / / leaked interrupts int s = state; if (s > = INTERRUPTING) handlePossibleCancellationInterrupt (s);}

There is a result = c.call () method, and the c here is the callable passed in Callable c = callable;, and callable is the WorkerRunnable we initially passed in the AsyncTask constructor, so then we should take a look at the call () method of WorkerRunnable, which mainly calls the doInBackground (mParams) and postResult (result) methods.

MWorker = new WorkerRunnable () {public Result call () throws Exception {mTaskInvoked.set (true); Process.setThreadPriority (Process.THREAD_PRIORITY_BACKGROUND); / / noinspection unchecked / / * * Result result = doInBackground (mParams); Binder.flushPendingCommands (); return postResult (result);}

1. Here we see the call to the doInBackground (mParams) method, which is still in the child thread, so time-consuming operations can be performed here. In the above case, the code in the doInBackground method will be executed, and when it is executed to the publishProgress () method, the progress information will be passed to the onProgressUpdate () method (later analysis will explain why the execution of publishProgress () can lead to the call to the onProgressUpdate () method), and let this method execute the update UI. At this point, the download interface in the case is as follows, and the progress is exactly 50%:

two。 At the end of the method, the postResult (result) method is executed, in which the result parameter is the return value of our doInBackground (mParams). The main function of this method is to create an instance of InternalHandler and send the what=MESSAGE_POST_RESULT message. Let's go on to look at the source code of this method.

Private Result postResult (Result result) {@ SuppressWarnings ("unchecked") Message message = getHandler (). ObtainMessage (MESSAGE_POST_RESULT, new AsyncTaskResult (this, result); message.sendToTarget (); return result;} / / sendToTarget () of the message method, and finally handler sends messages to a message queue public void sendToTarget () {target.sendMessage (this);}

Friends who are familiar with handler know that the target.sendMessage (this) method sends the message to the message queue, and the message carried is message itself. The message carries MESSAGE_POST_RESULT and new AsyncTaskResult (this, result) objects, which are sent by getHandler, and eventually it will handleMessage () (process the message), so we have to find this handler.

Private static Handler getHandler () {synchronized (AsyncTask.class) {if (sHandler = = null) {/ / create an InternalHandler instance named sHandler here sHandler = new InternalHandler ();} return sHandler;}}

According to the above getHandler () method, this handler object is InternalHandler, so the next task is to analyze the handlerMessage () method of InternalHandler, which is used to execute different logic based on different messages sent by sHandler in the postResult (Result result) method.

@ SuppressWarnings ({"unchecked", "RawUseOfParameterizedType"}) @ Overridepublic void handleMessage (Message msg) {AsyncTaskResult result = (AsyncTaskResult) msg.obj; switch (msg.what) {case MESSAGE_POST_RESULT: / / There is only one result result.mTask.finish (result.mData [0]); break; case MESSAGE_POST_PROGRESS: result.mTask.onProgressUpdate (result.mData); break }} / / result.mTask.finish (result.mData [0]) method is as follows: private void finish (Result result) {if (isCancelled ()) {onCancelled (result);} else {onPostExecute (result);} mStatus = Status.FINISHED;} / / result.mTask.onProgressUpdate (result.mData) @ MainThread protected void onProgressUpdate (Progress... Values) {}

As can be seen from the above source code, it carries out different message processing according to the different what information carried by msg. When what = MESSAGE_POST_RESULT, it will eventually execute onCancelled (result) or onPostExecute (result), both of which are executed in the main thread, and MESSAGE_POST_RESULT is passed in just when the information is obtained. When we download the code of the case here, we go to onPostExecute (result), and we hide the progress box with the following interface:

But where did the MESSAGE_POST_PROGRESS parameter come from? yes, it's publishProgress (Progress... Values)

@ WorkerThreadprotected final void publishProgress (Progress... Values) {if (! isCancelled ()) {getHandler () .obtainMessage (MESSAGE_POST_PROGRESS, new AsyncTaskResult (this, values)) .sendToTarget ();}}

MESSAGE_POST_PROGRESS is passed in here, and this method is called in WorkerThread. So onProgressUpdate (Progress... The values) method can be executed smoothly. The whole process is over.

Summary

1.AsyncTask objects can only create the 2.execute () method in the main thread and execute only 3. 5% in the UI thread. Do not call onPreExecute,onPostExecute,doInBackground,onProgressUpdate method 4. 0 directly in the program. An AsyncTask object can only execute the execute method once, otherwise it will report a runtime error. When the execute method is executed, the following code will be called to prove this conclusion.

If (mStatus! = Status.PENDING) {switch (mStatus) {case RUNNING: throw 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 be executed only once)");}}

5. Before Android1.6, AsyncTask executed tasks serially. After 1.6, it changed to parallel processing tasks in the thread pool, and after 3.0, it changed to serial execution tasks in the thread pool.

There are two thread pools (SerialExecutor and THREAD_POOL_EXECUTOR) and a handler (InternalHandler) in AsyncTask. SerialExecutor is used to queue tasks. In the above code, we have seen that we will call its execute method during the execution of AsyncTask.execute

Private static class SerialExecutor implements Executor {final ArrayDeque mTasks = new ArrayDeque (); 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);}

We see that the FutureTask object is first inserted into the queue mTask, and if there is no AsyncTask activity being executed at this time, scheduleNext () is called; the next task is executed, and the next task is executed after the completion of one task, which shows that AsyncTask is executed serially by default.

The above content is how to parse the android asynchronous message mechanism from the source code level. Have you learned the knowledge or skills? If you want to learn more skills or enrich your knowledge reserve, you are welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report