Android中Handler源码解析(一)
16lz
2021-12-04
1:处理消息的手段————Handler、Looper、MessageQueue 我们知道Android有主线程(UI线程)和子线程,所有的消息队列都会封装成消息在主线程中来处理,为了保证主线程不退出,消息放在一个死循环中如图所示: UI线程的循环是在ActivityThread.main方法中创建, ActivityThread,顾名思义,UI线程,也是Android整个应用的入口,代码如下所示:
消息运转的关键————Handler(必须在主线程中创建)创建示例如下:
每个Handler都会关联一个消息队列,消息队列又封装在Looper中,每个Looper又关联一个线程,说白了,Handler就是一个消息处理器,将消息post给消息队列,再由对应的线程逐个取出。那么问题来了,消息队列是如何创建的呢?
答:就是ActivityThread.main中 Looper . prepareMainLooper (); 方法 我们先看如下源码:
接着往下看:
从上面可以看到Looper是通过 sThreadLocal . get (); 获取到的,Looper是什么时候存到 sThreadLocal中的呢?如下:
这样队列就与线程关联上了 前面讲到Handlder与Looper的关联,所以Handler最终和队列、线程就关联上了 这也就解释清楚了:更新UI的时候为什么必须要在主线程中创建Handler,就是因为Handler要与主线程的消息队列进行关联
关联明白了,那么如何循环队列呢:答:通过Handler来Post消息给消息队列 那么消息是如何被处理的呢?我们明天继续分解
public static void main(String[] args) {
//代码省略
Process.setArgV0("" );
Looper.prepareMainLooper();//1:创建消息循环
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();//线程UI的Handler
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();//2:执行消息循环
throw new RuntimeException("Main thread loop unexpectedly exited");
}
消息运转的关键————Handler(必须在主线程中创建)创建示例如下:
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
// 更新UI
}
}
MyHandler mhandler = new MyHandler();
new Thread(){
public void run{
//耗时操作
mhandler.sendEmptyMessage(123);
};
}.start();
每个Handler都会关联一个消息队列,消息队列又封装在Looper中,每个Looper又关联一个线程,说白了,Handler就是一个消息处理器,将消息post给消息队列,再由对应的线程逐个取出。那么问题来了,消息队列是如何创建的呢?
答:就是ActivityThread.main中 Looper . prepareMainLooper (); 方法 我们先看如下源码:
public Handler(Callback callback, boolean async) {
//代码省略 mLooper = Looper.myLooper();//获取Looper
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;
}
Handler构造里面Looper.getLooper()来获取Looper对象并与之关联,它是怎么工作的呢? 下面来看看myLooper里面代码怎么实现的: public static Looper myLooper() {
return sThreadLocal.get();
}
接着往下看:
public static void prepareMainLooper() {
prepare(false);//见下
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException(
"The main Looper has already been prepared.");
}
sMainLooper = myLooper();//设置UI线程的Looper为当前Looper对象
}
}
// 为当前线程设置一个Looper
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是通过 sThreadLocal . get (); 获取到的,Looper是什么时候存到 sThreadLocal中的呢?如下:
这样队列就与线程关联上了 前面讲到Handlder与Looper的关联,所以Handler最终和队列、线程就关联上了 这也就解释清楚了:更新UI的时候为什么必须要在主线程中创建Handler,就是因为Handler要与主线程的消息队列进行关联
关联明白了,那么如何循环队列呢:答:通过Handler来Post消息给消息队列 那么消息是如何被处理的呢?我们明天继续分解
更多相关文章
- Android深入浅出之Binder机制
- [原]采用MQTT协议实现Android消息推送
- Android面试系列文章2018之Android部分IntentService机制篇
- android 加载图片轻松避免OOM(out of memory)
- Android(安卓)Configuration属性解析
- 彻底理解android binder通信架构
- Android(安卓)之 Looper Handler Message 之间的关系
- AsynTask 异步任务
- Android开发艺术探索—— 第十一章Android的线程和线程池