相关文章:
Handler的工作原理,为什么在子线程中执行 new Handler() 会抛出异常?
正文:
我们先来在子线程中创建一个Handler:
public class MyActivity2 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread("Thread1"){
@Override
public void run() {
super.run();
Handler handler = new Handler();
}
}.start();
}
}
按说是会报出异常的,但是很奇怪的是,根本没有报出任何异常!!!
下面写的也就不成立了!!
为此,特地新建了一个新项目,但是依然没有报出异常,真是见了鬼了。
放在onCreate()里面是不会报出异常的,如在其他声明周期方法或者点击时间里面,是会报出异常的。
异常如下:
E/AndroidRuntime: FATAL EXCEPTION: Thread1
Process: com.wzc.chapter_10, PID: 5263
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:208)
at android.os.Handler.<init>(Handler.java:122)
at com.wzc.chapter_10.MyActivity2$1.run(MyActivity2.java:20)
从日志里,可以知道:不能在还没有调用 Looper.prepare()
方法的线程中创建 Handler。
那我们就在线程中调用一次 Looper.prepare()
方法,再次运行果然不报错了。
Looper.prepare();
Handler handler = new Handler();
但是具体原因是什么?
从 Hander
的构造方法入手:
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> 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
对象为 null
的时候, 会抛出异常。说明这里的 Looper.myLooper();
的返回值是 null
。
看一下 Looper.myLooper()
方法:
public static Looper myLooper() {
return sThreadLocal.get();
}
是从 Looper
类 的 sThreadLocal
这个静态成员变量中取出 Looper
对象。
需要查看一下,sThreadLocal.set()
方法的调用:
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));
}
可以看到只有调用了 Looper.prepare()
方法,才会构造一个 Looper
对象并在 ThreadLocal
存储当前线程的 Looper
对象。
这样在调用 Looper.myLooper()
时,获取的结果就不会为 null
。