Yesterday I looked at the caching mechanism in Android and reviewed asynchronous loading tasks, especially AsyncTask. Since I usually use Handler to perform asynchronous tasks more often than AsyncTask, now I summarize my impression and share it with you. I’ll post a little bit about caching in Android in the next few days. In the process of writing this article, I used the first Line of Code, Android Development Art Exploration, a MOOC course and related blog posts for reference. The links are indicated at the end of the article. The following is a simple table of contents for this article.
- Asynchronous message processing mechanism
- Part of the
- The basic flow
- I met AsyncTask
- Basic introduction
- Execution order
- Matters needing attention
- The use of AsyncTask
- Loading network images
- Simulation progress bar
- AsyncTask is different from Handler
- source
- Program source code
## Asynchronous message processing mechanism
Asynchronous message processing is fundamental to Android development. In order to facilitate the understanding of AsyncTask later, I will briefly describe this mechanism, but it is not the focus of this article.
Asynchronous messaging in Android consists of four main parts:
- Message: the Message
- MessageQueue: MessageQueue
- Handler: Message Handler
- Looper: Message circulator
Let’s take a look at them one by one:
# # # # 1, the Message
Message is the Message that needs to be delivered in an asynchronous Message. It carries a small amount of information internally for data exchange between different threads. It itself has four fields that handle different types of information:
- What: Flags of the message, which can be processed differently depending on the flags
- Obj: The field is of type Object, which needs no explanation
- Arg1 and arg2: Integer types that can hold flag bits or hard-to-confuse integer values
# # # # 2, MessageQueue
This is easy to understand if you know Message, which is a Message queue. A queue contains a large number of messages that are not processed, so they are queued for processing. It is worth noting that there is only one MessageQueue object per thread.
####3, Handler this we are familiar with, not easy to translate, generally used to handle messages. Let’s call it a message handler. It is an important part of the processing mechanism for sending and processing messages. There are two main methods:
- SendMessage (Message MSG) : sends a Message
- HandleMessage (Message MSG) : Handles messages
That is, messages sent by the Handler will eventually be sent to the handleMessage, where they will be processed.
####4. Looper Looper is not well understood. The first line of code treats it as the butler of MessageQueue, which is abstract. Android Development Art Quest defines it as a message circulator, which is more logical. That is, when the thread Looper calls its loop() method, it enters an infinite loop that checks for messages in the MessageQueue. If there is an unprocessed message, Looper retrieves it. The handleMessage method passed to the Handler for processing.
Here we need to note two things:
- There is one and only one Looper object per thread.
- New threads do not have Looper, that is, only the UI Thread has Looper by default.
### Basic flow
With these basic definitions in mind, let’s look at the general flow of asynchronous message processing. Without further ado, picture above.
As can be seen from the figure, the general process is as follows:
- First we need to create a Handler object in the main thread and override the handleMessage method.
- Second, when the child thread needs to communicate with the main thread, it carries some information through the Message object and sends it through the Handler object.
- The message is sent to MessageQueue for processing.
- Looper does its job and loops until it detects a message waiting to be processed in the queue, immediately retrieves it and dispatches it to the handleMessage method so that the main thread receives the message and starts processing it.
I’ll leave it at that. If you don’t know anything about it, you can Google it. There are plenty of good posts. There are also related blog links at the end of the article, no further details.
# # AsyncTask person
AsyncTask is a lightweight asynchronous task class that, like Handler, performs tasks in the background. The process and results of executing the task can be returned to the main thread. So the main thread can do some UI updates.
It is essentially an abstract generic class, so we need to inherit the AsyncTask class when we use it:
public abstract class AsyncTask<Params,Progress,Result>
As you can see, the class provides three arguments:
- Params: parameter type to be entered when a task is started
- Progress: Type of Progress value returned during background task execution
- Result: Type of the Result returned after a background task is completed
At the same time, it has four core methods, which we look at in turn:
- OnPreExecute () : This method is executed in the main thread, usually the user does some preparation and initialization;
- doInBackground(Params… Params) : the key method for performing asynchronous tasks, executed in child threads, must be overridden. In this method, the publishProgress method is called to update the progress of the task, which in turn calls the onProgressUpdate method to update the progress. Note that this method needs to return a value to the onPostExecute method;
- onProgressUpdate(Progress… Values) : executed in the main thread for updating the task progress;
- OnPostExecute (Result Result) : Executed in the main thread, this method takes the return value of doInBackground.
There are other methods, but they are less common and I won’t cover them here (I don’t know).
After CustomTask inherits AsyncTask, you need to enable the task as follows:
new CustomTask().execute();
Of course, I did not write parameters here, in the actual development should be careful to fill in the corresponding parameters.
## order of execution
Let’s take a look at the execution order of the four core methods after we customize the Task and duplicate them. The test code is as follows:
/** * CustomTask extends AsyncTask<Void, Void, Void> {@override protected VoidonPreExecute() {
super.onPreExecute();
Log.w("Task"." ----> onPreExecute");
}
@Override
protected Void doInBackground(Void... params) {
publishProgress();
Log.w("Task"." ----> doInBackground");
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
Log.w("Task"." ----> onProgressUpdate");
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.w("Task"." ----> onPostExecute"); }}Copy the code
Look at the Log:
It can be seen that the execution sequence is:
onPreExecute -> doInBackground -> onProgressUpdate -> onPostExecute
### Note
Now that we have a basic understanding of AsyncTask, we need to be aware of some considerations and limitations in using it.
- Of the four core methods, only the doInBackground method runs on the child thread; the other methods run on the main thread.
- The AsyncTask class must be loaded on the main thread, that is, the first access to an AsyncTask must occur on the main thread.
- AsyncTask objects must be created in the main thread;
- The execute method of AsyncTask must be called in the main thread.
- The four core methods can only be automatically called by the system, but not actively called;
The use of # # AsyncTask
Now that you have a basic understanding of AsyncTask, let’s look at two examples of how AsyncTask can be used in a project.
### Load web images
Let’s start with the first Demo, which loads a web image using the URL of the image. It’s already a network image, of course it’s a time-consuming task, so we need to enable asynchronous tasks. Of course you can start a child thread to get it, but in this case we’re doing AsyncTask. The finished effect is as follows:
Look at the code, the code is relatively simple, the comments are also written very clear, I will not explain:
Public class NetPicActivity extends AppActivity {private ImageView netPicImage; private ProgressBar netPicProgressBar; private static String picUrl ="Http://www.iamxiarui.com/wp-content/uploads/2016/05/ wallpaper. JPG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_net_pic); netPicImage = (ImageView) findViewById(R.id.iv_netpic); netPicProgressBar = (ProgressBar) findViewById(R.id.pb_netpic); // Start processing asynchronous tasks by calling the execute method. New NetAsyncTask().execute(picUrl); } /** * extends AsyncTask<String, Void, Bitmap> {/** * onPreExecute for the operation before asynchronous processing */ @override protected voidonPreExecute() { super.onPreExecute(); / / sets the progressBar to VISIBLE. Here netPicProgressBar. SetVisibility (the VISIBLE). * * *} / indo* * @param The params parameter is URL * @returnBitmap object */ @override protected BitmapdoInBackground(String... Params) {// Get the parameter String url = params[0]; Bitmap bitmap = null; URLConnection connection; InputStream is; try { connection = new URL(url).openConnection(); is = connection.getInputStream(); // Sleep the Thread for 3 seconds thread. sleep(3000); BufferedInputStream bis = new BufferedInputStream(is); / / by decodeStream method resolution input stream bitmap. = BitmapFactory decodeStream (bis). is.close(); bis.close(); } catch (Exception e) { e.printStackTrace(); }returnbitmap; } /** * onPostExecute for UI updates. The argument to this method isdo@override protected void onPostExecute(bitmap bitmap) { super.onPostExecute(bitmap); / / hide progressBar netPicProgressBar. SetVisibility (View. GONE). / / update the imageView netPicImage. SetImageBitmap (bitmap); }}}Copy the code
By the way, be sure to remember to add network permissions, otherwise there is no effect.
### Simulate the progress bar
The onProgressUpdate method is not used to load the network image. Now we can use a progressupdate to load the network image.
Here we simulate the loading of the progress bar and call the publishProgress method in doInBackground to update the progress bar as follows:
Public class ProgressActivity extends AppCompatActivity {private ProgressBar mainProgressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(R.layout.activity_progress);
mainProgressBar = (ProgressBar) findViewById(R.id.pb_main);
//开启异步任务
new PbAsyncTask().execute();
}
/**
* 自定义异步任务类
*/
class PbAsyncTask extends AsyncTask<Void, Integer, Void> {
@Override
protected Void doInBackground(Void... Params) {// useforLoop to simulate the progress bar.for(int i = 0; i < 100; I ++) {// Calling the publishProgress method automatically triggers the onProgressUpdate method to update the progress bar. Thread.sleep(300); thread.sleep (300); } catch (InterruptedException e) { e.printStackTrace(); }}returnnull; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); / / by publishProgress method to get the value of the update of the progress bar. MainProgressBar. SetProgress (values [0]). }}}Copy the code
Note that when we look at the figure below, we can see that when the progress bar is not complete the first time, we go back and click to open the progress bar again. At this point, the progress bar does not start running. Instead, it starts to update the progress after a period of time.
Why is that? Because AsyncTask is implemented based on a thread pool, if one thread is not terminated, subsequent threads cannot execute. This means that the second task cannot be executed until the for loop of the first task has finished.
So how to solve it? We know that the Activity’s onPause() method is called when we click the BACK key, so we can mark the executing task as cancel in the Activity’s onPause() method, Cancel the previous task by checking the status of cancel during asynchronous processing in the doInBackground method.
The changed code looks like this:
Public class ProgressActivity extends AppCompatActivity {private ProgressBar mainProgressBar; private PbAsyncTask pbAsyncTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(R.layout.activity_progress); mainProgressBar = (ProgressBar) findViewById(R.id.pb_main); PbAsyncTask = new pbAsyncTask (); pbAsyncTask.execute(); } @Override protected voidonPause() {
super.onPause();
if(pbAsyncTask ! = null && pBASynctask.getStatus () == Asynctask.status.running) {// Cancel simply marks the corresponding AsyncTask as cancelt and does not actually cancel the thread. pbAsyncTask.cancel(true); Class PbAsyncTask extends AsyncTask<Void, Integer, Void> {@override protected VoiddoInBackground(Void... Params) {// useforLoop to simulate the progress bar.for(int i = 0; i < 100; I++) {// if task is in cancel state, it terminatesforLoop to execute the next task.if (isCancelled()) {
break; } // calling the publishProgress method automatically triggers the onProgressUpdate method to update the progress bar. Thread.sleep(300); thread.sleep (300); } catch (InterruptedException e) { e.printStackTrace(); }}returnnull; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); / / by publishProgress method to get the value of the update of the progress bar. MainProgressBar. SetProgress (values [0]). }}}Copy the code
The effect is as follows:
The cancel method only marks the corresponding AsyncTask as cancel, not the actual execution of the canceled thread. To actually cancel the thread, you still need to stop it in the doInBackground method.
AsyncTask is different from Handler
Having seen two demos, you should have a deep understanding of AsyncTask. But I have to wonder if it’s any different from starting a child thread. There is a big difference between AsyncTask and Handler.
Let’s start with AsyncTask, which is a lightweight asynchronous class provided by Android that can directly inherit from AsyncTask. Implement asynchronous operations in a class and provide an interface to feedback the current degree of asynchronous execution, known as progress updates, and finally feed back the results of the execution to the UI main thread. This method is simple and quick to use, the process is clear and easy to control. The downside is that when you use multiple asynchronous operations and need to make Ui changes, it gets complicated and the code looks bloated.
The second is Handler, which was introduced at the beginning of this article as asynchronous message processing. It processes messages through the connections between Handler, Looper, Message, and Thread. This approach is functionally cleaner, and the code looks more organized when there are multiple background tasks.
So in the actual development process, according to the need to choose the asynchronous task processing mode, as far as I am concerned, or the Handler mode is more used.
Ok, that’s the basic technique of this article. As my technical level is limited, if there are mistakes or different opinions, welcome to correct and exchange.
## Excellent source
Moocs – Android Must learn -AsyncTask Foundation
Android must learn asynctask-caobotao
Android message mechanism – Xiasuhuei321
AsyncTask and Handler are implemented and compared
## project source
Github – AsyncTaskDemo – IamXiaRui
Personal blog: www.iamxiarui.com the original link: http://www.iamxiarui.com/?p=699