Handler Looper( 二 )

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) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}
这是的其中一个构造方法,看到这么一段:
mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}
在构造方法里通过.()获取到一个对象,如果为空则报错,找到.()方法:
/*** Return the Looper object associated with the current thread.Returns* null if the calling thread is not associated with a Looper.*/public static @Nullable Looper myLooper() {return sThreadLocal.get();}
注释给出的解释是这个方法回返回跟当前线程相关联的对象,如果没有则返回空,还是没找到答案,接着找类里面对的定义:
// sThreadLocal.get() will return null unless you've called prepare().static final ThreadLocal sThreadLocal = new ThreadLocal();
又是注释里面告诉了我们重要信息,这里告诉我们只有你调用了.()方法.get()才不会返回空,那么说来说去还是要看.()的代码:
/** 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()}.*/public static void prepare() {prepare(true);}private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}
看下面那个,.()调用了()的重载方法( )并且传入了true参数,这个方法判断.get()是否会返回一个对象,如果没有的话就set一个新的进去,如果已经有了再调用()方法的话就会报错,不信邪的可以在创建之前也调用一个.(),控制台就会出现这个错误:

Handler Looper

文章插图
Crash
那么问题来了,为什么我们在主线程创建不需要调用.(),而在子线程中需要呢,可以合理的猜想是不是系统给我们主动调用了,毕竟我们大部分的操作还是在主线程上,每次都要那么.()来一次多麻烦,有了猜想还要去源码寻求验证,主线程是,从类里搜索相关信息,用跟上面一样的方法:
public static void main(String[] args) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");SamplingProfilerIntegration.start();// CloseGuard defaults to true and can be quite spammy.We// disable it here, but selectively enable it later (via// StrictMode) on debug builds, but using DropBox, not logs.CloseGuard.setEnabled(false);Environment.initForCurrentUser();// Set the reporter for event logging in libcoreEventLogger.setReporter(new EventLoggingReporter());// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);Process.setArgV0("");Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false);if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}