Android multithreading ----- explanation of AsyncTask, androidasynctask
You can clickBottom right cornerTo evaluate the content of the article.Follow buttonTo follow the latest developments in my blog. If the article content is helpful to you, do not forget to clickRecommendation buttonTo support a Oh if you have any questions about the content of the article, you can contact me by comment or mail: 501395377@qq.com/lzp501395377@gmail.com If You Need To reprint, please indicate the source, thank you !!
This article will explain how to use the AsyncTask mechanism to implement thread-to-thread communication.
I. multithreading in Android
In Android, when an application component is started and no other application component is running, the Android system opens a new thread for the application component to execute. By default, components in the same Android Application run in the same thread. This thread is called the Main thread. When we start another component through a component, this is done in the same thread by default. Of course, we can manage the threads of our Android Application by ourselves. We can create additional threads for the application according to our own needs.
Ii. Main Thread and Worker Thread
In Android, threads are generally divided into two types: Main Thread and Worker Thread.
When an application is running, the Android operating system starts a Thread for the application. This Thread is our Main Thread, which is very important, it is mainly used to load our UI, complete the interaction between the system and our users, and display the interaction results to our users. Therefore, Main Thread is also called UI Thread.
By default, the Android system does not create an additional thread for our application components. All these components are run in the same thread by default. However, in some cases, when our application needs to perform a time-consuming operation, such as accessing the network or querying the database, our UI Thread will be blocked. For example, when we click a Button and want it to obtain some data from the network, if this operation is completed in the UI Thread, when we click the Button, the UI thread will be in a blocking state. At this time, our system will not schedule any other events. What's worse, when the blocking time on our entire site exceeds 5 seconds (officially speaking), ANR (Application Not Responding) will occur, the application will pop up a box asking the user to choose whether to exit the program. For Android development, ANR is absolutely not allowed.
In addition, because our Android UI controls are Thread-insecure, we cannot operate our UI controls in threads other than UI threads. Therefore, in the multi-thread programming of Android, we have two very important principles that must be followed:
- We absolutely cannot perform time-consuming operations in the UI Thread, nor block our UI Thread
- We cannot manipulate our UI elements in threads other than the UI Thread.
3. How to handle the communication between the UI Thread and Worker Thread
Since there are two important principles to follow in Android, we may have questions? We can neither process time-consuming operations in the main thread nor access our UI controls in the working thread. For example, if we want to download an image from the network, how can I update it to the UI control? This is related to the communication problem between our main thread and working thread. In Android, two methods are provided to solve the direct thread communication problem, one is through the Handler mechanism (this method will be described in detail later ), there is also an AsyncTask mechanism to be explained in detail today.
Iv. AsyncTask
AsyncTask: asynchronous tasks, literally, perform some operations asynchronously when the main UI thread is running. AsyncTask allows us to execute an asynchronous task in the background. We can place time-consuming operations in asynchronous tasks for execution, and return the task execution results to our UI thread at any time to update our UI control. With AsyncTask, we can easily solve the communication problem between multiple threads.
How to Understand AsyncTask? Generally speaking, AsyncTask is equivalent to a framework provided by Android for multi-threaded programming, which is between Thread and Handler. If we want to define an AsyncTask, define a class to inherit the abstract class AsyncTask and implement its unique doInBackgroud abstract method. To master AsyncTask, we must have a concept. In summary, there are three generic types and four steps.
What do the three generic types mean? Let's take a look at the definition of the abstract class AsyncTask. When we define a class to inherit the class AsyncTask, We need to specify three generic parameters for it:
AsyncTask <Params, Progress, Result>
- Params: This generic type specifies the parameter type that we pass to the asynchronous task for execution.
- SS: This generic type specifies the type of parameters that our asynchronous task returns the execution progress to the UI thread during execution.
- Result: The type of the result returned to the UI thread after the asynchronous task is executed.
When defining a class to inherit the AsyncTask class, we must specify these three generic types. If none of them are specified, they are all written as Void. For example:
AsyncTask <Void, Void, Void>
4 steps: When we execute an asynchronous task, perform the following 4 steps:
- OnPreExecute ():This method is executed before the asynchronous task is executed and is executed in the UI Thread. We usually perform initialization operations on some UI controls in this method, for example
- DoInBackground (Params... params ):This method will be executed immediately after the onPreExecute () method is executed. This method is used to process asynchronous tasks, the Android operating system starts a worker thread in the background thread pool to execute this method. Therefore, this method is executed in the worker thread, after this method is executed, we can send our execution results to our last onPostExecute method. In this method, we can obtain data from the network and perform some time-consuming operations.
- OnProgressUpdate (Progess... values ):This method is also executed in the UI Thread. During asynchronous task execution, we sometimes need to return the execution progress to our UI interface, such as downloading a network image, we need to display the download progress at any time, so we can use this method to update our progress. Before calling this method, we need to call a publishProgress (Progress) method in the doInBackground method to transfer our Progress to the onProgressUpdate Method for update at all times.
- OnPostExecute (Result... result ):After an asynchronous task is executed, the result is returned to this method, which is also called in the UI Thread. We can display the returned result on the UI control.
Why does our AsyncTask abstract class have only one abstract doInBackground method ?? The reason is that if we want to do an asynchronous task, we must open up a new Thread for it to complete some operations. When we complete this asynchronous task, I may not need to bring up the ProgressDialog. I do not need to update the progress bar of my ProgressDialog at any time, and I do not need to update the results to our UI interface, therefore, all three methods except the doInBackground method are not required. Therefore, we must implement the doInBackground method.
5. Use AsyncTask to download an image from the network
The following two sample codes show how to use AsyncTask to download an image from the network and update it to our ImageView control.
① When downloading an image, a ProgressDialog is displayed, but the real-time progress is not displayed.
Let's take a look at the layout file:
<RelativeLayout xmlns: android = "http://schemas.android.com/apk/res/android" xmlns: tools = "http://schemas.android.com/tools" android: layout_width = "match_parent" android: layout_height = "match_parent"> <ImageView android: id = "@ + id/imageView" android: layout_width = "wrap_content" android: layout_height = "200dp" android: layout_alignParentRight = "true" android: layout_alignParentTop = "true" android: scaleType = "fitCenter"/> <Button android: id = "@ + id/button" android: layout_width = "wrap_content" android: layout_height = "wrap_content" android: layout_below = "@ + id/imageView" android: layout_centerHorizontal = "true" android: layout_marginTop = "41dp" android: text = "download an image from the Internet"/> </RelativeLayout>
It is a simple ImageView control and a Button control. When you click the Button control, a ProgressDialog pops up, starts an asynchronous task, and downloads an image from the network, and update it to our ImageView. Note that if we want to use a mobile phone to access the network, we must authorize it. In the future study, we will explain in detail the authorization knowledge in Android. Let's take a look.
AndroidManifest. xml file:
<? Xml version = "1.0" encoding = "UTF-8"?> <Manifest xmlns: android = "http://schemas.android.com/apk/res/android" package = "com. xiaoluo. android_asynctast "android: versionCode =" 1 "android: versionName =" 1.0 "> <uses-sdk android: minSdkVersion =" 8 "android: targetSdkVersion =" 18 "/> <! -- Authorize the mobile phone to access the network --> <uses-permission android: name = "android. permission. INTERNET "/> <application android: allowBackup =" true "android: icon =" @ drawable/ic_launcher "android: label =" @ string/app_name "android: theme = "@ style/AppTheme"> <activity android: name = "com. xiaoluo. android_asynctast.MainActivity "android: label =" @ string/app_name "> <intent-filter> <action android: name =" android. intent. action. MAIN "/> <category android: name =" android. intent. category. LAUNCHER "/> </intent-filter> </activity> </application> </manifest>
Next let's take a look at our Activity code:
Public class MainActivity extends Activity {private Button button; private ImageView imageView; private ProgressDialog progre; private final String IMAGE_PATH = "http://developer.android.com/images/home/kk-hero.jpg"; // private final String IMAGE_PATH2 = "http://ww2.sinaimg.cn/mw690/69c7e018jw1e6hd0vm3pej20fa0a674c.jpg "; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); button = (Button) findViewById (R. id. button); imageView = (ImageView) findViewById (R. id. imageView); // The mainssdialog progreprogre= new ProgressDialog (MainActivity. this); progressDialog. setTitle ("prompt message"); progressDialog. setMessage ("Download in progress. Please wait ...... "); // setCancelable (false); indicates that the pop-up box cannot be canceled. After the download is complete, the pop-up box will disappear progressDialog. setCancelable (false); // set the ProgressDialog style to "ssdialog" in the form of a circle. setProgressStyle (ProgressDialog. STYLE_SPINNER); button. setOnClickListener (new View. onClickListener () {@ Override public void onClick (View v ){
// Instantiate the AsyncTask object in the UI Thread and call the execute method new myasynctask(cmd.exe cute (IMAGE_PATH) ;}});}/*** to define a class, inherit the AsyncTask class * Params: String type, which indicates that the parameter type passed to the asynchronous task is String. Generally, the URL path * Progress: Integer type is specified, the progress bar is usually of the Integer type * Result: byte [] type, indicating that the downloaded image returns * @ author xiaoluo **/public class MyAsyncTask extends AsyncTask <String, integer, byte [] >{@ Override protected void onPreExecute () {super. onPreExecu Te (); // In onPreExecute (), let ProgressDialog display progressDialog. show () ;}@ Override protected byte [] doInBackground (String... params) {// use Apache's HttpClient to access an image in the request network. HttpClient httpClient = new DefaultHttpClient (); HttpGet httpGet = new HttpGet (params [0]); byte [] image = new byte [] {}; try {HttpResponse httpResponse = httpClient.exe cute (httpGet); HttpEntity httpEntity = httpResponse. getEntity (); If (httpEntity! = Null & httpResponse. getStatusLine (). getStatusCode () = HttpStatus. SC _ OK) {image = EntityUtils. toByteArray (httpEntity) ;}} catch (Exception e) {e. printStackTrace ();} finally {httpClient. getConnectionManager (). shutdown () ;}return image ;}@ Override protected void onProgressUpdate (Integer... values) {super. onProgressUpdate (values) ;}@ Override protected void onPostExecute (byte [] result) {super. onPostExecute (result); // decodes byte [] returned by the doInBackground method to Bitmap bitmap = BitmapFactory. decodeByteArray (result, 0, result. length); // update our ImageView control imageView. setImageBitmap (bitmap); // disappears the ProgressDialog box. dismiss () ;}@ Override public boolean onCreateOptionsMenu (Menu menu) {getMenuInflater (). inflate (R. menu. main, menu); return true ;}}
Let's take a look:
② Download a network image with a progress bar update
The following code example shows the update of the progress bar and the configuration files remain unchanged when downloading images. Let's take a look at the Activity code:
Public class MainActivity extends Activity {private Button button; private ImageView imageView; private ProgressDialog progre; private final String IMAGE_PATH = "http://developer.android.com/images/home/kk-hero.jpg"; // private final String IMAGE_PATH2 = "http://ww2.sinaimg.cn/mw690/69c7e018jw1e6hd0vm3pej20fa0a674c.jpg "; @ Override protected void onCreate (Bundle savedInstanceState) {super. on Create (savedInstanceState); setContentView (R. layout. activity_main); button = (Button) findViewById (R. id. button); imageView = (ImageView) findViewById (R. id. imageView); // The mainssdialog progreprogre= new ProgressDialog (MainActivity. this); progressDialog. setTitle ("prompt message"); progressDialog. setMessage ("Download in progress. Please wait ...... "); // setCancelable (false); indicates that the pop-up box cannot be canceled. After the download is complete, the pop-up box will disappear progressDialog. setCanc Elable (false); // set ssdialog to a horizontal style ProgressDialog. setProgressStyle (ProgressDialog. STYLE_HORIZONTAL); button. setOnClickListener (new View. onClickListener () {@ Override public void onClick (View v) {new myasynctask(.exe cute (IMAGE_PATH) ;}});}/*** defines a class, inherit the AsyncTask class * Params: String type, which indicates that the parameter type passed to the asynchronous task is String. Generally, the URL path * Progress: Integer type is specified, the progress bar is usually of the Integer type * Result: byte [] type, indicating that the download is successful. * @ Author xiaoluo **/public class MyAsyncTask extends AsyncTask <String, Integer, byte [] >{@ Override protected void onPreExecute () {super. onPreExecute (); // In onPreExecute (), let ProgressDialog display progressDialog. show () ;}@ Override protected byte [] doInBackground (String... params) {// use HttpClient of Apache to access an image in the request network. HttpClient httpClient = new DefaultHttpClient (); HttpGet httpGet = n Ew HttpGet (params [0]); byte [] image = new byte [] {}; try {HttpResponse httpResponse = httpClient.exe cute (httpGet); HttpEntity httpEntity = httpResponse. getEntity (); InputStream inputStream = null; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream (); if (httpEntity! = Null & httpResponse. getStatusLine (). getStatusCode () = HttpStatus. SC _ OK) {// obtain the total length of the object long file_length = httpEntity. getContentLength (); // The accumulated length after each read: long total_length = 0; int length = 0; // read 1024 bytes of byte [] data = new byte [1024] each time; inputStream = httpEntity. getContent (); while (-1! = (Length = inputStream. read (data) {// For each read, The total_length is accumulated total_length + = length; // ByteArrayOutputStream is written to byteArrayOutputStream while reading. write (data, 0, length); // get the progress of the current image download int progress = (int) (total_length/(float) file_length) * 100 ); // update the current progress to the onProgressUpdate method publishProgress (progress);} image = byteArrayOutputStream. toByteArray (); inputStream. close (); byteArrayOutputStream. close ();} catch (Exception e) {e. printStackTrace ();} finally {httpClient. getConnectionManager (). shutdown () ;}return image ;}@ Override protected void onProgressUpdate (Integer... values) {super. onProgressUpdate (values); // update the progress bar ProgressDialog. setProgress (values [0]);} @ Override protected void onPostExecute (byte [] result) {super. onPostExecute (result); // decodes byte [] returned by the doInBackground method to Bitmap bitmap = BitmapFactory. decodeByteArray (result, 0, result. length); // update our ImageView control imageView. setImageBitmap (bitmap); // disappears the ProgressDialog box. dismiss () ;}@ Override public boolean onCreateOptionsMenu (Menu menu) {getMenuInflater (). inflate (R. menu. main, menu); return true ;}}
Let's take a look:
In this way, we can use AsyncTask to download an image from the network, update it to the UI control, and update the current progress at all times.
Vi. Important knowledge points of AsyncTask
The working principles of AsyncTask have been explained in the above two sections. Here we will add some other knowledge points of AsyncTask:
1. Cancelling a Task
We can cancel the execution of our asynchronous task at any time. By calling the cancel (boolean) method, the system then calls the isCancelled () method and returns true. If this method is called, The onPostExecute () method is not called after the doInBackgroud () method is executed. Instead, the onCancelled () method is called. To ensure that the Task has been canceled, we need to call the isCancelled () method frequently to determine if necessary.
2. the principles that must be followed when AsyncTask is used for asynchronous tasks:
- The AsyncTask class must be loaded in the UI Thread, which is automatically completed after the Android Jelly_Bean version
- The AsyncTask object must be instantiated in the UI Thread.
- The execute method must be called in the UI Thread.
- Do not manually call the onPreExecute, doInBackground, publishProgress, onProgressUpdate, and onPostExecute methods of AsyncTask. These methods are automatically called by the Android system.
- The AsyncTask task can be executed only once.
At this point, the AsyncTask summary ends. This article mainly describes the multi-thread knowledge in Android and explains in detail the concept and implementation mechanism of AsyncTask asynchronous tasks, we also learned about the execution process of AsyncTask through examples, and finally supplemented some important knowledge points of AsyncTask, including how to cancel an AsyncTask and the rules we must follow when using AsyncTask.