If you're deciding whether a thread is the main line in Android? For this question, you might say that according to the thread's name, of course this solves the problem, but is it the most reliable? In case one day, Google will be the thread of the name of the other god horse things.
Method revealed
The following approach is the most reliable solution.
Copy Code code as follows:
public static Boolean Isinmainthread () {
return Looper.mylooper () = = Looper.getmainlooper ();
}
In fact, write here basically solve the problem of the title of the article, but only to study here is too superficial, not deep enough, so need to continue, I hope you can continue reading.
Inquisitive
Experiment One
OK, now, let's do some testing on this stable method, first of all, the following method will add some debugging printing information.
Copy Code code as follows:
Private Boolean isinmainthread () {
Looper mylooper = Looper.mylooper ();
Looper mainlooper = Looper.getmainlooper ();
LOG.I (LogTag, "Isinmainthread mylooper=" + mylooper
+ "; mainlooper=" + mainlooper);
return mylooper = = Mainlooper;
}
OK, then we run a test in the main thread and invoke the above method. Like we call this.
Copy Code code as follows:
LOG.I (LogTag, "Testinmainthread inmainthread=" + isinmainthread ());
OK, let's take a look at the output log. Verify OK.
Copy Code code as follows:
I/testinmainthread (32028): Isinmainthread Mylooper=looper{40d35ef8};mainlooper=looper{40d35ef8}
I/testinmainthread (32028): Testinmainthread inmainthread=true
Experiment II
Now we're going to go ahead and validate it in a non main thread without a message loop.
Copy Code code as follows:
New Thread () {
@Override
public void Run () {
LOG.I (LogTag, "Testin not in Mainthread ismainthread="
+ Isinmainthread ());
Super.run ();
}
}.start ();
As we can see the following log results, the main thread of the Looper (translated into the circulation pump, not very nice) has been initialized to assign value. But the looper of our newly created thread is still null. This is because the thread in Android does not default to a message loop that is bound to it (Threads by default does not have a messages loop associated with them. Of course, the method works)
Copy Code code as follows:
I/testinmainthread (32028): Isinmainthread Mylooper=null;mainlooper=looper{40d35ef8}
I/testinmainthread (32028): Testin not in Mainthread ismainthread=false
Experiment Three
Continue, we create a thread that binds the message loop, according to the Android developer documentation, here is a typical example of creating a message loop thread, using the separate prepare () method and the loop () method to create a handler bound to Looper.
Copy Code code as follows:
New Thread () {
Private Handler Mhandler;
@Override
public void Run () {
Looper.prepare ();
Mhandler = new Handler () {
public void Handlemessage (msg) {
Process incoming messages here
}
};
LOG.I (LogTag, "Testinnonmainlooperthread ismainthread="
+ Isinmainthread ());
Looper.loop ();
}
}.start ();
OK, now check the following log again,
Copy Code code as follows:
I/testinmainthread (32028): Isinmainthread Mylooper=looper{40d72c58};mainlooper=looper{40d35ef8}
I/testinmainthread (32028): Testinnonmainlooperthread ismainthread=false
Two looper are initialized, but they are different objects.
Principle excavation
But what is this, and what mysteries are there? OK, let's look at the following Looper.class
Copy Code code as follows:
Sthreadlocal.get () would return null unless for you ' ve called prepare ().
Static final threadlocal<looper> sthreadlocal = new threadlocal<looper> ();
private static Looper smainlooper; Guarded by Looper.class
/**
* Initialize The current thread as a looper, marking it as a
* application ' s main looper. The main looper for your application
* are created by the "Android environment, so" should never need
; * To call this function yourself. the also: {@link #prepare ()}
*/
public static void Preparemainloope R () {
prepare (false);
synchronized (looper.class) {
if (smainlooper!= null) {
throw new IllegalStateException ("The main looper has already been.");
}
smainlooper = Mylooper ();
}
}
private static void Prepare (Boolean quitallowed) {
if (sthreadlocal.get ()!= null) {
throw new RuntimeException ("Only one looper could created per thread");
}
Sthreadlocal.set (New Looper (quitallowed));
}
/**
* Return the Looper object associated with the current thread.
* Returns NULL if the calling thread is isn't associated with a looper.
*/
public static Looper Mylooper () {
return Sthreadlocal.get ();
}
/** Returns The application ' s main Looper, which lives in the main thread of the application.
*/
public static Looper Getmainlooper () {
Synchronized (Looper.class) {
return smainlooper;
}
}
For the main thread, Preparemainlooper this method will be invoked by the Android runtime, rather than by the program's explicit invocation. In this way, the looper of the main thread is created and the object reference is passed to Smainlooper. So the reference that the main thread mylooper () gets and Getmainlooper () gets is guaranteed to be the same reference.
For a looper thread without a message loop, the default current thread is NULL because you never call prepare () manually, so it is not the same as the looper of the main thread.
For a non main thread that is bound to a message loop, When the Looper.prepare method is invoked, the looper of the main thread is already created by the Android runtime Environment, and when the prepare method is invoked, the Looper bound to the non main thread is created, which, of course, is not the same as the main thread's looper.
To sum up, this method is reliable.