Sometimes we need to create some in the applicationresident Sub-threads perform some computational tasks irregularly, you can consider using Handlerthread, which hascreating a child thread with a message loop's role.
First, Handerthread use exampleFamiliarize yourself with the general usage of the Handlerthread first. We create an activity that looks like this:
Package Com.example.handlethreaddemo;import Android.app.activity;import Android.os.bundle;import Android.os.handler;import Android.os.handlerthread;import Android.os.looper;import Android.os.Message;import Android.util.log;public class Mainactivity extends Activity{private Looper mlooper;private MyHandler mHandler;private Static final String TAG = "mainactivity";p rivate static class MyHandler extends Handler{public MyHandler (Looper Looper) {su Per (Looper);} @Overridepublic void Handlemessage (Message msg) {switch (msg.what) {case 1:log.i (TAG, "Current thread is" +thread.currentthread (). GetName () + ", Test 1"), Break;case 2:log.i (TAG, "Test 2"); @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview ( R.layout.activity_main);//Create Handlerthread object Handlerthread myhandlethread = new Handlerthread ("handlerthread< child thread > ");//start handlerthread----> internal will start message loop Myhandlethread.start ();//Get Loopermlooper = Myhandlethread.getlooper (); /construct handler, incoming LOOPERMHA in child threadsNdler = new MyHandler (mlooper); * * Note: After the above steps, handler will bind the Looper and MessageQueue of the child thread. * That is to say Handlemessage finally calls the child thread * */mhandler.sendemptymessage (1); LOG.I (TAG, "Current thread is:" +thread.currentthread (). GetName ());}}
Constructs a handler object using the Looper object provided internally by Handlerthread, and then sends a message to handler in the UI thread. Log logs are as follows:
The thread that sends the message is visible as the UI thread, and the thread that processes the message is a child thread, which means we
a message loop is created in a child thread。 In general, we always create the handler object in the UI thread and use the default Looper provided by the interface component, which is bound on the UI thread. So when we send a message to handler in a thread, the final processing takes place in the main thread. But as the opening point says, we sometimes need to build a resident sub-thread to perform computational tasks irregularly, and it is useful to create a message loop in a child thread.
Second, handlerthread source analysisHandlerthread source code is very streamlined. Handlerthread inherits from Java.lang.Thread and encapsulates the Looper object:
int mpriority;//priority int mtid = -1;//thread flag Looper mlooper;//message loop
thread priority can be injected through the constructor, with the default priority of Process.thread_priority_default
Public Handlerthread (String name, int priority) { super (name); Mpriority = priority; }
The core logic is the Run method (the Run method of the replication thread Class):
public void Run () { Mtid = Process.mytid (); Looper.prepare ();//Create Looper Object synchronized (this) { mlooper = Looper.mylooper ();//Get Looper bound to this thread Notifyall (); } Process.setthreadpriority (mpriority); Onlooperprepared ();//callback interface, default is an empty implementation. Looper.loop ();//Start message loop--->may be blocked Mtid =-1; }
The Looper object can be obtained by the outside world through the Getlooper method:
Public Looper Getlooper () { if (!isalive ()) {//thread death return null; } If The thread has been started, wait until the Looper have been created. Synchronized (this) { while (isAlive () && mlooper = = null) { try { wait ();//asynchronously waits for Looper to be ready } catch (Interruptedexception e) { }}} return mlooper; }
If Looper is not ready when the Getlooper method is called, the thread will be blocked until the Looper object is ready. The outside can call the Quit method to terminate the message loop:
public Boolean Quit () { Looper Looper = Getlooper (); if (looper! = null) { looper.quit ();//Internal calls the Looper class's quit return true; } return false; }
Attached: Looper class believe that everyone is not unfamiliar, here by the way simply mention (previously written handler and Looper): The Looper.prepare method will create a Looper object (the constructor of the Looper class is private, not new), and put it in threadlocal, meaning thread-local variables:
public static void Prepare () { prepare (true); } private static void Prepare (Boolean quitallowed) { if (sthreadlocal.get () = null) { throw new RuntimeException (" Only one Looper could be created per thread "); Sthreadlocal.set (New Looper (quitallowed)); }
The Looper.mylooper method is then used to return the Looper bound to this thread, which is the looper that was just created:
public static Looper Mylooper () { return sthreadlocal.get (); }
The Looper.loop method initiates the message loop and continuously extracts the message from its internally encapsulated Message Queuing MessageQueue and is referred to the handler execution.
public static void Loop () {final Looper me = Mylooper (); if (me = = null) {throw new RuntimeException ("No Looper; Looper.prepare () wasn ' t called on this thread. "); Final MessageQueue queue = Me.mqueue; Make sure the identity of the the the the The local process,//and keep track of what the identity toke n actually is. Binder.clearcallingidentity (); Final Long ident = Binder.clearcallingidentity (); for (;;) {Message msg = Queue.next ();//might block if (msg = = NULL) {//No Message Indicat ES the message queue is quitting. Return }//This must is in a local variable, in case a UI event sets the logger Printer logging = Me.mlogg ing if (logging! = null) {logging.println (">>>>> dispatching to" + Msg.target + "" + Msg.callback + ":" + msg.what); } msg.target.dispatchMessage (msg); if (logging! = null) {logging.println ("<<<<< finished to" + Msg.target + "" + Msg.callbac k); }//Make sure that during the course of dispatching the//identity of the thread wasn ' t corrupted. Final Long newident = Binder.clearcallingidentity (); if (ident! = newident) {LOG.WTF (TAG, "Thread identity changed from 0x" + Long.tohex String (ident) + "to 0x" + long.tohexstring (newident) + "when dispatching to" + Msg.target.getClass (). GetName () + "" + Msg.callback + "what=" + msg.what); } msg.recycle (); } }
Message Queuing is blocked when there is no message.
The above is the whole content of handlerthread.
"Android Notes" Handlerthread source analysis