Android Looper、Handler与Message邂逅
来源:互联网 发布:p2p网贷软件系统 编辑:程序博客网 时间:2024/05/20 12:24
前言
太久没更新会让大家觉得我是个很懒的人, 这也一直困扰着我, 学不到东西,以后怎么找工作啊, 不说了,很快就要找实习了,赶紧备些干货.
Looper
每个线程都只可以有一个Looper
Looper无非就是先Looper.prepare(),再Looper.loop()
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));}private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { return; } ... ... try { msg.target.dispatchMessage(msg); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } ... msg.recycleUnchecked(); }}
上面代码省略了一些打印的代码, 大家可以清晰地看到
prepare()里会new 一个Looper, 但是会先判断如果已存在Looper就抛出异常
Looper的构造方法, 创建MessageQueue和绑定当前的线程
loop方法, 最主要还是for无限循环里,每次读取一条消息,然后交给msg.target.dispatMessage方法.再回收每条消息的资源
Looper的主要作用就是
绑定当前线程,同时一个Looper也只有一个MessageQueue
loop()方法,不断从MessageQueue中取消息,然后交给消息的target属性的dispatchMessage去处理
Handler
Handler是如何与MessageQueue联系的, 而又是如何在子线程发送消息到MessageQueue的.
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;}
可以从倒数的第8和第3行看出来, Handler就这样跟MessageQueue联系上了
下面我们看看经常使用的sendMessage方法
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis);}public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis);}public final boolean sendMessageDelayed(Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis);}
最终的调用是sendMessageAtTime(…), 而刚刚好,这里有MessageQueue, 我们就很清楚地看到Handler与MessageQueue的互动
继续看enqueueMessage()方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis);}
之前我们Looper里有写到msg.target, 这里的target在上面赋值为这个handler, 然后调用MessageQueue的enqueueMessage方法将msg插入到消息队列中
现在我们更加清楚了,接下来继续看明白dispatchMessage方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}
这里出现了callback, 首先我们理清一下逻辑
如果msg.callback不为null, 就直接调用handler.handleCallback(msg)
如果msg.callback为null, 那么继续如果mCallback不为null, 并且如果mCallback成功处理消息,那么return, 否则, 调用handler.handleMessage(msg)
看看什么是handleMessage
public void handleMessage(Message msg) {}
源代码是空的, 为什么呢, 不知道大家还记不记得, 经常使用Handler的时候,都会重写handleMessage方法然后根据msg.what来进行操作
总结
- Looper.prepare方法初始化Looper,创建MessageQueue消息队列,然后使用loop方法想MessageQueue无限读取消息,回调msg.target.dispatchMessage方法
- Handler的初始化, 绑定当前线程的Looper和MessageQueue, 重写handleMessage方法, 根据msg.what进行相应的UI更新
为什么使用时没有看到Looper.prepare方法
那是因为Activity启动的时候就已经在当前UI线程调用了Looper.prepare()方法和Looper.loop()方法了
相关知识
MessageQueue
虽然叫做’消息队列’,其实是一个单链表
前面讲到msg会通过queue.嗯queueMessage()方法插入队列中, 同理还有取得下个消息的方法next(), 这里就不一一贴代码了
主要是想讲一下, 如果队列没有消息或者有延迟的消息, 这里就会阻塞.然后会回调监听阻塞的观察者
Looper如何停止
有两种方法, Looper.quit(), Looper.quitSafely(), 同种都是调用MessageQueue.quit(boolean)方法
quit() :立即回收所有消息, 这个是不安全的, 一般使用quitSafely()
quitSafely() : 回收没执行的消息
参考资料
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
- Android Looper、Handler与Message邂逅
- Android:Message、Handler、Message Queue与Looper
- Android Handler、Message、MessageQueue与Looper介绍
- Android Handler,Looper,Message
- Android - Looper / Handler / Message
- Android Handler Message Looper
- Android Handler 、 Looper 、Message
- Handler、Looper、Message与HandlerThread
- Android进程 Handler Message Looper
- Android进程 Handler Message Looper
- Android Handler Message Looper 机制
- Android MessageQueue,Message,Looper,handler
- android线程handler、message、looper
- Android Handler + Looper + Message理解
- android handler looper message区别
- Android Handler Looper Message MessageQueue
- Android Looper Handler 和Message
- Android Looper Message MessageQueue Handler
- 实现定位
- Springboot系列:Springboot与Thymeleaf模板引擎整合基础教程(附源码)
- mysql server for linux
- POJ 3481 Double Queue
- 注册QML类型
- Android Looper、Handler与Message邂逅
- Java设计模式之代理模式
- Oracle里数据库与实例的区别以及windows下如何创建数据库及对应的实例
- 输入一串正整数,输出组合后最大的数
- HTTP中请求转发和重定向的区别
- 科大讯飞编程题 2018 课程冲突
- 实验一:写一个hello world小程序
- SENet(Squeeze-and-Excitation Networks)算法笔记
- 【UVA1289】Stacking Plates