这里写自定义目录标题
关于Handler的一些思考
1.在子线程中可以创建handler吗?
答案是可以的
//错误示例
new Thread(){
@Override
public void run() {
new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
}
}.start();
如果按上述方法直接创建Handler,会报运行时错误
为什么会抛这个异常呢?
看下Handler源码
handler的空构造函数中调用handler的有参构造函数,第一行代码
//获取当前线程的looper
mLooper = Looper.myLooper();
就是从Looper中获取当前线程的Looper,接着判断当前线程的Looper是否为空,如果为空,就上面的抛出异常。
回到这个问题,那我们在子线程又该如何正确的创建handler呢,其实很简单,就如异常信息所提示的,在当前线程创建handler之前需要初始化当前线程的looper,即Looper.prepare()。无论是主线程还是子线程的Looper创建,都是通过Looper的prepare()函数创建的,我们看下prepare函数的源码
子线程一般调用的是Looper.prepare(),prepare()里面调用
p
r
e
p
a
r
e
(
t
r
u
e
)
\color{#FF0000}{prepare(true)}
prepare(true) ,主线程调用的是prepareMainLooper,里面是调用
p
r
e
p
a
r
e
(
f
a
l
s
e
)
\color{#FF0000}{prepare(false)}
prepare(false) ,我们注意到,他们都是调用了prepare(allowQuit)有参函数,这个参数是什么意思呢?true表示允许退出,所以当不需要这个线程的时候可以调用Looper的quit()函数,false则代表不允许退出.
另外需要注意的是,在prepare()和prepareMianLooper()函数中,都会判断当前线程是否已经存在looper对象,如果已经存在了,会抛出异常,
每
个
线
程
只
允
许
有
一
个
L
o
o
p
e
r
\color{#FF0000}每个线程只允许有一个Looper
每个线程只允许有一个Looper
我们看下创建Looper的源码:
创建MessageQueue,在messageQueue中保存quitAllowed参数,并在Native层执行初始化操作nativeInit()。
2.主线程的Looper与主线程的Looper有什么区别
区别:
- 主线程的Looper是不可以退出的(在prepare的时候传的quiteAllowed是false,子线程传的是false),子线程的looper是可以退出的,调用looper.quit()即可
- 子线程的looper需要自己去调用prepare(),而主线程的Looper在进程启动的时候就已经自动创建好了
3.Looper和MessageQueue有什么关系
在java层,looper与messageQueue是一对一的关系,在创建looper对象的时候就会创建messageQueue对象,在创建messageQueue的时候,会调用native层的nativeinit,对native层的looper和messageQueue进行初始化
4.MessageQueue是如何创建的?
在java层创建Looper对象的时候会创建messageq的java对象,而在创建messageQueue的java对象时,又会调用native层的nativeinit,创建native层的looper和messageQueue