「这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战」
上篇文章我们介绍的子线程中向主线程发送消息。
主线程向子线程发送消息
new Thread(new Runnable(){
@Override
public void run() {
Looper.prepare();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 处理消息
switch (msg.what) {
case 1:
Log.d(TAG, "接收到消息: "+msg.obj);
break;
default:
break;
}
}
};
Looper.loop();
}
}).start();
Button button=findViewById(R.id.bt);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "来自主线程的消息";
// 向子线程中发送消息
handler.sendMessage(msg);
}
});
复制代码
上述代码我们可以看出来,两者的实现基本相同,最大的区别就是在子线程中创建Handler之前调用Looper.prepare(),之后调用Looper.loop()方法。但是为什么在主线程中不需要呢,其实在系统主线程中系统已经创建好了。
public static void main(String[] args) {
//...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
}
复制代码
主线程中Looper的创建在ActivityThread.main方法中,是App的入口。
- Looper.prepareMainLooper(),其实调用的Looper。loop,初始化Looper、MessageQueue等。
- 在创建ActivityThread的同时初始化了成员变量Handler mH.
- 将成员变量mH赋值给sMainThreadHandler
- 最后调用Looper.loop()开启死循环,从MessageQueue中不断取出Message消息去处理。
这就是主线程中创建Looper的流程。
Handler机制原理
Handler机制主要设计四部分:Message、Hanlde、Looper、消息队列。
1.Looper
首先先了解其构造方法。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
复制代码
在创建Looper时会初始化MessageQueue对象。最重要的就是prepare( ) 和 loop( )这两个方法,下面对其分别进行分析。
prepare()
调用关系:Looper.prepare()->prepare(true)
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
//一个线程创建一个looper对象
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
复制代码
将创建的Looper对象存放在ThreadLocal,ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据,这样就保证了一个线程对应了一个 Looper,从源码中也可以看出一个线程也只能有一个 Looper
,否则就会抛出异常。
loop()
后续继续介绍。