During the Android development process, the time-consuming operation is not allowed to write in the main thread (UI thread), so as not to cause the ANR to wait too long. So time-consuming operations need to create sub-threads to complete, but often these operations need to communicate with the main thread (such as updating the UI of the main thread), but Android rules that no other thread can access or manipulate the UI controls except the UI thread. So we need some way to implement these functions.
1. Handler:
Handler is a tool that is specifically used to pass information classes between threads in Android. API Reference: Https://developer.android.google.cn/reference/android/os/Handler
1. Call Looper.prepare and looper.loop in the B thread. (not required for main thread)
2, write the handler class, rewrite the Handlemessage method.
3. Create an instance of the handler class and bind the Looper
4. Call handler's Sentmessage method to send the message.
- Child threads update the main thread (UI)
Because the main thread comes with the looper mechanism, all we don't have to create looper:
Handler Mhandler = new Handler () {@Override
public void Handlemessage (Message msg) { super .handlemessage (msg); switch (msg.what) { case 1: // do Something,refresh UI; break ; default : break ; } } };
Then turn on a sub-thread and send the message directly in the thread using handler:
New Thread () { publicvoidnew Message ();
= "message Hi~hi sent by the child thread"; Mhandler. SendMessage (message);
};}. Start ();
- Interaction between child threads
public class Threadactivity extends Appcompatactivity {
Private final String TAG = "threadactivity";
Child Thread Handler
Private Handler Msubhandler = null;
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.LAYOUT.ACTIVITY_THREAD1);
New MyThread (). Start ();
CreateThread ();
}
/**
* Create sub-threads for sending messages
*/
private void CreateThread () {
New Thread () {
@Override
public void Run () {
int count = 0;
while (Count < 10) {
Message msg = new Message ();
msg.obj = "Child thread Timer:" + count;
Msg.what = 1;
To send a message using a child thread handler
Msubhandler.sendmessage (msg);
try {
Thread.Sleep (1000);
} catch (Interruptedexception e) {
E.printstacktrace ();
}
count++;
}
}
}.start ();
}
/**
* For receiving the message sent by the Cheng of the Strand.
*/
Class MyThread extends Thread {
@Override
public void Run () {
Looper.prepare ();
Msubhandler = new Handler () {
@Override
public void Handlemessage (Message msg) {
Switch (msg.what) {
Case 1:
LOG.I (TAG, (String) msg.obj);
Break
}
}
};
Looper.loop ();
}
}
}
2. Handlerthread:
Handlerthread is a thread that contains Looper, and we can create Handler directly using this Looper. API Reference: Https://developer.android.google.cn/reference/android/os/HandlerThread
The handlerthread is suitable for single-threaded + asynchronous Queue model scenarios, with relatively handler + thread simplicity.
You can also implement the Run method
Handlerthread Mhandlerthread =NewHandlerthread ("Handlerthread_test"); Mhandlerthread.start (); Handler Mthreadhandler=NewHandler (Mhandlerthread.getlooper ()) {@Override Public voidhandlemessage (Message msg) {Switch(msg.what) { Case1: log.i (TAG,"threadname--" + thread.currentthread (). GetName () +(String) msg.obj); Break; } }}; //Send message to HanderthreadMthreadhandler.sendmessage (msg);
3. Runonuithread
The Runonuithread (Runnable) method in the Activity allows the child thread to update the UI more succinctly. There are also View.post (Runnable) and view.postdelayed (Runnabe,long) methods, which are basically the same usage as runonuithread.
NewThread (NewRunnable () {@Override Public voidrun () {Try{Thread.Sleep (1000 ); } Catch(interruptedexception e) {e.printstacktrace (); } runonuithread (NewRunnable () {@Override Public voidrun () {//Performing UI ActionsToast.maketext (mainactivity. This, "Test", Toast.length_short). Show (); } }); }}). Start ();
4. Asynctask
API Reference: Https://developer.android.google.cn/reference/android/os/AsyncTask
Asynctask is an abstract class that is a lightweight asynchronous class that is packaged by Android. It can perform background tasks in the thread pool and then pass the progress and final results of the execution to the main thread and update the UI in the main thread. Asynctasks should be used for short operations (up to a few seconds). If you need to keep threads running for a long time, it is highly recommended that you use the various APIs provided by the Java.util.concurrent package, such as Executor,threadpoolexecutor and Futuretask. An asynchronous task is defined by 3 generic types: Params,progress and result, and 4 steps: Onpreexecute,doinbackground,onprogressupdate and OnPostExecute.
You need to inherit the Asynctask class when using Asynctask and must implement Doinbackground (params ...). Method, the OnPostExecute (Result) method needs to be implemented in most cases.
Private classDownloadfilestaskextendsAsynctask<url, Integer, long> { protectedLong doinbackground (URL ... urls) {intCount =urls.length; LongTotalSize = 0; for(inti = 0; I < count; i++) {totalsize+=Downloader.downloadfile (Urls[i]); Publishprogress ((int) ((I/(float) count) * 100)); //Escape Early if cancel () is called if(IsCancelled ()) Break; } returntotalsize; } protected voidOnprogressupdate (Integer ... progress) {setprogresspercent (progress[0]); } protected voidOnPostExecute (Long result) {ShowDialog ("Downloaded" + result + "bytes"); }}
It is easy to perform a task after a successful creation:
New Downloadfilestask (). Execute (URL1, URL2, URL3); Params
Generic type of Asynctask:
- Params: The type of argument passed to the task at execution time;
- Progress: The type of execution progress value is returned during asynchronous task execution;
- Result: The results type of the background task execution.
Not all types must be used in asynchronous tasks, instead of void if they are not required.
class extends Asynctask<void, Void, void> {...}
When performing an asynchronous task, there are 4 steps to go through:
- onpreexecute (): Called in the UI mainline and before the asynchronous task executes. This step is typically used to set up tasks, such as displaying a progress bar in the notes interface.
- doinbackground (Params ...) : OnPreExecute () immediately calls this method in the background thread when it finishes executing. This step is used to perform a potentially long running background task, with parameters by execute (params ...). Incoming. Use this procedure to get the results and return to the last step. During the calculation, you can call Publishprogress (Progress ...). method, and through Onprogressupdate (Progress ...) The update UI displays the progress of the task execution.
- onprogressupdate (Progress ...) : When Publishprogress (Progress ...) After the method executes, this step is called in the UI main thread and updates the UI current task progress.
- onpostexecute (Result) : Called on the UI thread after the background thread calculation is complete. The results of a background thread calculation are passed as parameters to this step.
Asynctask also provides the oncancelled () method, which is also executed in the main thread, and when the asynchronous task is canceled, oncancelled () is called, and OnPostExecute () is not invoked at this time, but it is important to note that The Cancel () method in Asynctask is not really going to cancel the task, just set the task to cancel the state, we need to judge the Doinbackground () to terminate the task. Just like you want to terminate a thread, call the Interrupt () method, just mark it as interrupted, need to be tagged inside the thread to judge and then break the thread.
The following issues also need to be noted with Asynctask:
- An instance of an asynchronous task must be created in the UI thread, that is, the Asynctask object must be created in the UI thread.
- Execute (Params ...) must be executed on the UI thread.
- Do not manually call OnPreExecute (), OnPostExecute (Result), Doinbackground (Params ...), Onprogressupdate (Progress ...) Method.
- The task can only be executed once (an exception is thrown if an attempt is performed on the second execution).
- You cannot change the information for the UI component in the Doinbackground (params. params).
- Asynctask does not bind the life cycle with any component, so it is best to call Cancel (Boolean) in Activity/fragment () when creating execution asynctask in activity/or fragment;
- If Asynctask is declared as a non-static inner class of activity, then Asynctask retains a reference to the activity that created the asynctask. If the activity has been destroyed, Asynctask's background thread is still executing, and it will continue to keep the reference in memory, causing the activity to not be recycled, causing a memory leak.
- Screen rotation or activity being killed in the background by the system will cause the activity to be recreated, and the previously running Asynctask (non-static inner class) will hold a reference to the previous activity, which is invalid, when called OnPostExecute ( ) to update the interface will no longer be effective.
Asynctask There are two kinds of thread pools for us to call, and the default is to use Serial_executor. The core thread of the Asynctask is 5, the queue capacity is 128, and the maximum number of threads is 9.
- Thread_pool_executor, an asynchronous thread pool.
- Serial_executor, synchronize the thread pool.
A simple example of Asynctask:
Custom Asynctask:
classTestasynctaskextendsAsynctask<integer, Integer, integer>{@Overrideprotectedinteger doinbackground (integer ... integers) {intCount = Integers[0]; intLen = integers[1]; while(Count <Len) { intPro = * Count/Len; LOG.I (TAG,"----------" + Pro + ":" + Count + ":" +Len); Publishprogress (PRO); Try{Thread.Sleep (100); } Catch(interruptedexception e) {e.printstacktrace (); } Count++; } returncount; } @Overrideprotected voidonprogressupdate (Integer ... values) {Mtext.settext ("Progress:" + values[0] + "%"); } @Overrideprotected voidonpostexecute (Integer integer) {mtext.settext ("Finished:" + integer + "%"); }}
To create an Testasynctask instance:
Masynctask.execute (0, 100);
Android Thread Interaction