publicHandler() { this(null, false); } publicHandler(Callback callback, boolean async) { if (FIND_POTENTIAL_LEAKS) { final Class<? extendsHandler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } }
mLooper = Looper.myLooper(); if (mLooper == null) { thrownewRuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
可以看到我们平常写的 new Handler();其实是调用了另外一个构造方法,并且判断了mLooper是不是为空,为空则抛出一个异常**”Can’t create handler inside thread that has not called Looper.prepare()”**,mLooper其实是一个Looper类的成员变量,官方文档上对Looper类的解释是 **Class used to run a message loop for a thread.**也就是说Looper用于在一个线程中传递message的。 然后我们根据异常的提示知道要在new一个Handler的对象之前必须 先调用Looper.prepare()。那接下来就只能先去看看Looper.prepare()方法了:
/** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference * this looper, before actually starting the loop. Be sure to call * {@link #loop()} after calling this method, and end it by calling * {@link #quit()}. */ publicstaticvoidprepare() { prepare(true); }
privatestaticvoidprepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { thrownewRuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(newLooper(quitAllowed)); }
/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */ publicstaticvoidloop() { finalLooperme= myLooper(); if (me == null) { thrownewRuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } finalMessageQueuequeue= me.mQueue;
// Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); finallongident= Binder.clearCallingIdentity();
for (;;) { Messagemsg= queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; }
// This must be in a local variable, in case a UI event sets the logger Printerlogging= me.mLogging; 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.callback); }
// Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. finallongnewIdent= Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); }
msg.recycleUnchecked(); } }
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ publicstatic@Nullable Looper myLooper() { return sThreadLocal.get(); }