android-handler、looper、messageQueue、message
Handler创建,必须有个一个Looper,主线程自己创建了。其他线程需要自己创建,默认是没有的。创建方法
1. 这种方法是先创建一个系统定义好的HandlerThread,这个是跑在非UI线程中的,已经创建好了looper,直接用就可以了.创建handler有多个构造函数,具体看源码
HandlerThread threadhandler = new HandlerThread("1111");
threadhandler.start();
myhandler = new myHandler(threadhandler.getLooper());
2. 自己创建一个新的线程,在线程中调用Looper.prepare();然后写处理message回调方法,接着还要调用looper.loop();
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
为什么一定要有一个Looper呢? 因为handler的无参数构造函数里需要looper,如果为空就抛异常。 如何设置looper? 调用Looper.prepare();这里会判断当前的线程是不是已经有looper了,有的话会抛异常,这就是说一个线程只能有一个looper。 Message是什么,有什么用? 存放消息的用的,它有很多属性。特别说明target,表示的就是处理它的handler,next属性,这就是利用了链表结构来构造的消息队列,message.next表示着当前消息的下一个,是按照时间来的,只能顺序不能反过来,他没有prev属性。 这里需要说一下他的Spool静态属性,这是一个消息池,Spool自己就是一个Message对象,刚开始的时候他是null的,什么时候它有东西的呢?
void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } } 看这个方法,这个方法是looper中循环处理完一个message之后做的事情,它回收了这个message,并且将这个被回收的message和已有的Spool链接起来,再将Spool指向这个回收的message,利用这种方法将回收的message都给串了起来。 message -> spool -> null spool(被回收的message)-> message(旧的spool) -> null 消息池怎么被使用的? public static Message obtain() {
synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
利用obtain的方法得到一个消息池中的第一个空message,并且spool指向第二个元素,剩余的空消息数-1; MessageQueue是什么,有什么用? 用来操作messages,例如handler发送消息过来,他需要把消息按照顺序串起来。还有处理完消息后他需要把消息从消息队列中删除等等。 handler有什么用? 发送和处理消息。handler通过sendmessage等方法发送消息,最终都是通过sendMessageAtTime(这里最终是调用了enqueueMessage方法,其中uptimeMillis参数是SystemClock.uptimeMillis() + delayMillis,所以想要优先处理runable,就是要让时间戳在所有message之前,利用
sendMessageAtFrontOfQueue方法,这个参数会传递0,这样就会优先处理了)来处理发送给MessageQueue。然后通过looper回调函数msg.target.dispatchMessage(msg)-->handler的handleMessage()方法具体处理。
handler还可以使用post方法将runnable传给消息队列message有callback属性,在looper的dispatchMessage()方法中,如果是runnable就直接run()了; 最后有个疑问:到底是什么样的机制可以让looper循环去处理message?
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
return;
}
if (me.mLogging!= null) me.mLogging.println( ">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what );
msg.target.dispatchMessage(msg);
if (me.mLogging!= null) me.mLogging.println( "<<<<< Finished to " + msg.target + " "
+ msg.callback);
msg.recycle();
}
看到Message msg = queue.next(); // might block 这句话,获得待处理的message,这里可能会堵塞,没有message的时候就循环等待,直到messageQueue退出 现在再看看queue.next方法
if (msg != null && msg.target == null) { // Stalled by a barrier. Find the next asynchronous message in the queue. do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); }
这部分代码进入条件是target是null,那么什么时候target会是null呢,首先我们要明确,我们只有2种方法往messageQueue的mMessages里插入message---enqueueMessage(sendMessage等最终都是走的它)和enqueueBarrier。我们用handler在setMessage的时候enqueueMessage方法已经
msg.target = this; 而且如果我们使用的是带参数的Message中的obtain方法也会设置target。 那么无疑就是enqueueBarrier方法,这个方法只有一个入口,就是Looper的postSyncBarrier(),它会返回一个int值,用于之后的removeSyncBarrier(int)。
int enqueueSyncBarrier(long when) { // Enqueue a new sync barrier token. // We don't need to wake the queue because the purpose of a barrier is to stall it. synchronized (this) { final int token = mNextBarrierToken++; final Message msg = Message.obtain();//这里返回一个target为null的Message msg.markInUse(); msg.when = when; msg.arg1 = token; ..... } } 然后接着看queue.next,如果是阻断msg,那么就一直找到msg是isAsynchronous的,然后接着处理,这个isAsynchronous有2种设置方法,一个是handler构造参数里面传的,那么所有的sendMessage都会打上异步标签。还有一种就是单独调用一个message的setAsynchronous。 这样的话,当阻断的时候就会跳过普通的message,找到异步message去执行。 接着往下看next();
// Got a message. mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next;//如果阻断的话,这里prevMsg就不是空,那么就会直接把标签是异步的message的上一个message的next直接指向标签是异步的message的下一个message,其实就是把异步message从消息队列中给抽出去了
} else { mMessages = msg.next;//这里就是普通message的处理步骤,消息队列少了第一个元素 } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); return msg; 到这里,阻断message还是在消息队列中,下次循环还是依照这个顺序执行。除非我们手动调用removeSyncBarrier方法才能正常处理普通的message。
这里得到个结论,mMessages的第一个元素不一定就是本次待处理的message。
这个阻断在源码中有地方使用:scheduleTraversals这个方法,这个方法是view的measure,layout,draw三部曲的入口。
void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; mTraversalBarrier = mHandler.getLooper().postSyncBarrier();//这里,使用了阻断,此时只有message是异步的才可以被执行。 mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); if (!mUnbufferedInputDispatch) { scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); }}
mTraversalRunnable这个Runnable执行的代码是
void doTraversal() { if (mTraversalScheduled) { mTraversalScheduled = false; mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);//已经开始执行了,就把阻断remove掉,view展示完毕后继续正常处理普通的message if (mProfile) { .... } } }优点快速展示,想了半天,为啥他不使用sendMessageAtFrontOfQueue这个方法优先执行mTraversalRunnable呢?可能原因,我们也可以主动调用改方法,那么岂不是就有可能我们的runnable优先与系统展示view了?使用阻断,他内部还是按照时间戳顺序执行的,就保证了view展示优先执行~!!!!!
接着看next();
// Run the idle handlers.// We only ever reach this code block during the first iteration.for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; // release the reference to the handler boolean keep = false; try { keep = idler.queueIdle(); } catch (Throwable t) { Log.wtf("MessageQueue", "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); } }}
这里还有代码,这是干嘛的?这这个就是执行idle handlers的,当之前的message,一个都找不到的时候,说明空闲,这个时候就可以执行IdleHandler了使用方法就是调用MessageQueue的addIdleHandler方法。
转载于:https://www.cnblogs.com/liming-saki/p/4515283.html
android-handler、looper、messageQueue、message相关推荐
- Android中的Handler、Looper和MessageQueue的使用以及原理
提到Handler大家一定都不陌生,通常我们都是在子线程通过在主线程中创建的Handler对象切换到主线程中去更新View的显示内容,然而很少接触Looper更没有感觉到MessageQueue的存在 ...
- Handler、Looper与MessageQueue源码分析
在Android中可以通过Handler来更新主线程中UI的变化,更新UI只能在主线程中进行更新,而为了让其他线程也能控制UI的变化,Android提供了一种机制Handler.Looper与Mess ...
- Android Handler与Looper原理简析
一直感觉自己简直就是一个弱智,最近越来越感觉是这样了,真的希望自己有一天能够认同自己,认同自己. 本文转载于:https://juejin.im/post/59083d7fda2f60005d14ef ...
- Handler与looper、MessageQueue的关系
Handler与Looper.MessageQueue的关系 1. Handler机制? 只要遵循Android使用handler来更新UI的机制,我们就不用关心多线程的问题,所有的更新UI的操作都是 ...
- android handler的机制和原理_一文搞懂handler:彻底明白Android消息机制的原理及源码
提起Android消息机制,想必都不陌生.其中包含三个部分:Handler,MessageQueue以及Looper,三者共同协作,完成消息机制的运行.本篇文章将由浅入深解析Android消息机制的运 ...
- Android Handler的原理
简介 在 Android 中,只有主线程才能操作 UI,但是主线程不能进行耗时操作,否则会阻塞线程,产生 ANR 异常,所以常常把耗时操作放到其它子线程进行.如果在子线程中需要更新 UI,一般是通过 ...
- Android进阶知识树——Android Handler消息机制
1.概述 在安卓程序启动时,会默认在主线程中 运行程序,那如果执行一些耗时的操作则UI就会处于阻塞状态,出现界面卡顿的现象,再者用户的多种操作,系统是如何做到一一处理的,系统又是如何管理这些任务的,答 ...
- Android Handler杂记(结合别人的blog)
handler泄露问题: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1123/2047.html http://blog.c ...
- Android多线程源码学习笔记一:handler、looper、message、messageQueue
最近在学习Android多线程相关知识的源码,现在把自己的笔记整理一下,写出来加深印象. Android多线程通讯的核心是handler.looper.message.messageQueue,这篇文 ...
- android handler、looper、message、messageQueue、
一:handler,looper,message,messagequeue,thread handler: 消息处理着,负责Message消息的发送(handler.sendMessage(....) ...
最新文章
- vfprintf php,PHP vfprintf() 函数
- STM32系列--初识寄存器1
- 【软考-软件设计师】校验码
- OpenGL基本窗口和OpenGL 初始化
- “==”和equals()那些事
- c++ socket线程池原理_ThreadPoolExecutor线程池实现原理+源码解析
- 让经纬度数据带矢量方向_惊艳!这样处理可得到细至可用于交通模型的路网数据...
- 【技术人快报】美军计划换用Linux系统+安卓系统“克隆漏洞”曝光
- 回溯算法背包问题迭代c语言,回溯法解决0_1背包问题(迭代和递归)
- 诺基亚N9手机升级后PR1.3后反应迟钝、发热、耗电快的问题
- 照片宽高比怎么设置_2019年中级会计报名照片上传完整攻略
- Gauss光束在空间中的分布
- Vue学习--黑马电商管理系统
- c语言数组及其下标引用,C语言之数组下标引用与间接引用
- 《数据结构》第五章 树和二叉树 同学问题收集站
- ttk progress bar的显示
- Android 360开源全面插件化框架RePlugin 实战
- 双排桩弯矩Matlab求解程序,考虑开挖过程椅式双排桩内力及变形分析
- 《东周列国志》第五十一回 责赵盾董狐直笔 诛斗椒绝缨大会
- 2019年计算机二级获证条件,2019年下半年全国计算机等级考试报考简章