当前位置: 首页 > news >正文

网站建设招标评分表网店如何营销推广

网站建设招标评分表,网店如何营销推广,高考志愿网站开发,网络营销推广好做吗Handler postDelayed的实现原理 问题描述 Handler.postDelayed()的原理是如何保证延时执行的? 扩展:这样实现的好处是什么? 题目分析 猜测一下 以我们对Handler的了解,内部使用了Looper对消息队列进行循环获取执行&#xff0…

Handler postDelayed的实现原理

问题描述

Handler.postDelayed()的原理是如何保证延时执行的?
扩展:这样实现的好处是什么?

题目分析

猜测一下

以我们对Handler的了解,内部使用了Looper对消息队列进行循环获取执行,所以我们估计postDelayed()是Handler内部搞了一个定时器,
定时器到了delayed的时间就把消息加入到消息队列中,让looper在循环获取到该消息并执行。

真的是这样吗?如果不是,为什么?

我们来追溯一下源码

消息是怎样入队的?

首先调用的是sendMessageDelayed方法


public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {return sendMessageDelayed(getPostMessage(r), delayMillis);}
sendMessageDelayed计算了消息执行的准确时间,当前时间加上延时时间public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}public boolean sendMessageAtTime(@NonNull 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);}private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,long uptimeMillis) {msg.target = this;msg.workSourceUid = ThreadLocalWorkSource.getUid();if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}  
Message的enqueueMessage方法boolean enqueueMessage(Message msg, long when) {if (msg.target == null) {throw new IllegalArgumentException("Message must have a target.");}if (msg.isInUse()) {throw new IllegalStateException(msg + " This message is already in use.");}synchronized (this) {if (mQuitting) {IllegalStateException e = new IllegalStateException(msg.target + " sending message to a Handler on a dead thread");Log.w(TAG, e.getMessage(), e);msg.recycle();return false;}msg.markInUse();msg.when = when;Message p = mMessages;boolean needWake;if (p == null || when == 0 || when < p.when) {// New head, wake up the event queue if blocked.msg.next = p;mMessages = msg;needWake = mBlocked;} else {// Inserted within the middle of the queue.  Usually we don't have to wake// up the event queue unless there is a barrier at the head of the queue// and the message is the earliest asynchronous message in the queue.needWake = mBlocked && p.target == null && msg.isAsynchronous();Message prev;for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;}if (needWake && p.isAsynchronous()) {needWake = false;}}msg.next = p; // invariant: p == prev.nextprev.next = msg;}// We can assume mPtr != 0 because mQuitting is false.if (needWake) {nativeWake(mPtr);}}return true;}

查看源码我们发现:并不是像我们推测的那样使用定时器加入队列,而是简单计算了消息开始执行的时间之后就加入队列了。
MessageQueue中Message的结构就是一个简单的单向链表,只保存了链表头部的引用。
我们分析一下入队过程

if (p == null || when == 0 || when < p.when) {// New head, wake up the event queue if blocked.msg.next = p;mMessages = msg;needWake = mBlocked;} else {···}

如果链表头为空或者延时时间已经到了,则放到列表头,唤醒阻塞队列

for (;;) {prev = p;p = p.next;if (p == null || when < p.when) {break;}if (needWake && p.isAsynchronous()) {needWake = false;}}msg.next = p; // invariant: p == prev.nextprev.next = msg;

否则遍历链表,安装when的时间顺序插入消息,注意when = SystemClock.uptimeMillis() + delayMillis

Looper是如何出来延时消息的?

我们看看Looper的loop()方法

for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}...

原来是调用了MessageQueue的next方法,注释说明会阻塞。

我们看下MessageQueue的next方法里面做了啥?


Message next() {// Return here if the message loop has already quit and been disposed.// This can happen if the application tries to restart a looper after quit// which is not supported.final long ptr = mPtr;if (ptr == 0) {return null;}int pendingIdleHandlerCount = -1; // -1 only during first iterationint nextPollTimeoutMillis = 0;for (;;) {if (nextPollTimeoutMillis != 0) {Binder.flushPendingCommands();}nativePollOnce(ptr, nextPollTimeoutMillis);synchronized (this) {// Try to retrieve the next message.  Return if found.final long now = SystemClock.uptimeMillis();Message prevMsg = null;Message msg = mMessages;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());}if (msg != null) {if (now < msg.when) {// Next message is not ready.  Set a timeout to wake up when it is ready.nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);} else {// Got a message.mBlocked = false;if (prevMsg != null) {prevMsg.next = msg.next;} else {mMessages = msg.next;}msg.next = null;if (DEBUG) Log.v(TAG, "Returning message: " + msg);msg.markInUse();return msg;}} else {// No more messages.nextPollTimeoutMillis = -1;}// Process the quit message now that all pending messages have been handled.if (mQuitting) {dispose();return null;}// If first time idle, then get the number of idlers to run.// Idle handles only run if the queue is empty or if the first message// in the queue (possibly a barrier) is due to be handled in the future.if (pendingIdleHandlerCount < 0&& (mMessages == null || now < mMessages.when)) {pendingIdleHandlerCount = mIdleHandlers.size();}if (pendingIdleHandlerCount <= 0) {// No idle handlers to run.  Loop and wait some more.mBlocked = true;continue;}if (mPendingIdleHandlers == null) {mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];}mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);}// 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 handlerboolean keep = false;try {keep = idler.queueIdle();} catch (Throwable t) {Log.wtf(TAG, "IdleHandler threw exception", t);}if (!keep) {synchronized (this) {mIdleHandlers.remove(idler);}}}// Reset the idle handler count to 0 so we do not run them again.pendingIdleHandlerCount = 0;// While calling an idle handler, a new message could have been delivered// so go back and look again for a pending message without waiting.nextPollTimeoutMillis = 0;}}

原来在next方法中对链表头部的Message的执行时间进行了判断,如果当前时间小于msg.when,则计算阻塞时间,
然后在循环开始的时候判断如果这个Message有延迟,就调用nativePollOnce(ptr, nextPollTimeoutMillis)进行阻塞。
有兴趣的童鞋可以下Android源码看看native层的nativePollOnce是如何实现的,作用与object.wait()类似,只不过是使用了Native的方法对这个线程精确时间的唤醒。
唤醒之后loop()就能拿到对应的message了。

参考答案

1、比如postDelay()一个延时10秒钟的Runnable A、消息进队,MessageQueue调用nativePollOnce()阻塞,Looper阻塞;

2、紧接着post()一个Runnable B、消息进队,判断现在A时间还没到、正在阻塞,把B插入消息队列的头部(A的前面),然后调用nativeWake()方法唤醒线程;

3、MessageQueue.next()方法被唤醒后,重新开始读取消息链表,第一个消息B无延时,直接返回给Looper;

4、Looper处理完这个消息再次调用next()方法,MessageQueue继续读取消息链表,第二个消息A还没到时间,计算一下剩余时间(假如还剩9秒)继续调用nativePollOnce()阻塞;
直到阻塞时间到或者下一次有Message进队再次唤醒;

比我们的猜测好在哪里?

1、如果用我们的猜测方案,我们每添加一个延时消息就需要维护一个定时器,如果消息多耗费性能极大;

2、使用定时器到了延时时间再加入队列,如果队列中任务比较多,则延时的精度会大大降低,精度不如Google的方案。


文章转载自:
http://blooper.c7623.cn
http://brutally.c7623.cn
http://transmountain.c7623.cn
http://cyanosed.c7623.cn
http://micropore.c7623.cn
http://chimerism.c7623.cn
http://reiterative.c7623.cn
http://insurance.c7623.cn
http://retinae.c7623.cn
http://equanimously.c7623.cn
http://tatpurusha.c7623.cn
http://stormcoat.c7623.cn
http://looie.c7623.cn
http://megagametophyte.c7623.cn
http://flix.c7623.cn
http://archer.c7623.cn
http://scrobiculate.c7623.cn
http://comfrey.c7623.cn
http://thorpe.c7623.cn
http://professorship.c7623.cn
http://declarator.c7623.cn
http://scrophulariaceous.c7623.cn
http://epistyle.c7623.cn
http://unflawed.c7623.cn
http://aequorin.c7623.cn
http://alike.c7623.cn
http://plenary.c7623.cn
http://flaxweed.c7623.cn
http://folkland.c7623.cn
http://prelife.c7623.cn
http://geocentricity.c7623.cn
http://spiff.c7623.cn
http://adventism.c7623.cn
http://christianization.c7623.cn
http://flywheel.c7623.cn
http://dowry.c7623.cn
http://dishpan.c7623.cn
http://alkylic.c7623.cn
http://diomedes.c7623.cn
http://vastness.c7623.cn
http://enteropathogenic.c7623.cn
http://minnesotan.c7623.cn
http://rifleman.c7623.cn
http://palmetto.c7623.cn
http://intraswitch.c7623.cn
http://governor.c7623.cn
http://gelatiniferous.c7623.cn
http://wels.c7623.cn
http://turco.c7623.cn
http://paramorphism.c7623.cn
http://quadrilled.c7623.cn
http://innumerability.c7623.cn
http://underpants.c7623.cn
http://cyo.c7623.cn
http://hydronium.c7623.cn
http://sonlike.c7623.cn
http://tribromoethanol.c7623.cn
http://hankow.c7623.cn
http://bandkeramik.c7623.cn
http://agriology.c7623.cn
http://cressida.c7623.cn
http://khi.c7623.cn
http://gimpy.c7623.cn
http://flinch.c7623.cn
http://whiskified.c7623.cn
http://crip.c7623.cn
http://merchandize.c7623.cn
http://undisguisedly.c7623.cn
http://evocable.c7623.cn
http://crystal.c7623.cn
http://goatsucker.c7623.cn
http://tristearin.c7623.cn
http://elenctic.c7623.cn
http://buckayro.c7623.cn
http://outsat.c7623.cn
http://leukemic.c7623.cn
http://xantippe.c7623.cn
http://diseconomy.c7623.cn
http://legging.c7623.cn
http://translucence.c7623.cn
http://zhejiang.c7623.cn
http://remanent.c7623.cn
http://acapriccio.c7623.cn
http://noctambulism.c7623.cn
http://breadth.c7623.cn
http://eto.c7623.cn
http://kheth.c7623.cn
http://arresting.c7623.cn
http://transpositional.c7623.cn
http://vaccinee.c7623.cn
http://busboy.c7623.cn
http://notalgia.c7623.cn
http://undergo.c7623.cn
http://dipteran.c7623.cn
http://disparaging.c7623.cn
http://sentimentalise.c7623.cn
http://growly.c7623.cn
http://hypotactic.c7623.cn
http://commenter.c7623.cn
http://disallowable.c7623.cn
http://www.zhongyajixie.com/news/52375.html

相关文章:

  • 关于 公司网站建设的通知搜狗seo快速排名公司
  • ppt成品免费下载seo外链发布技巧
  • 政府网站平台日常制度建设网络热词缩写
  • 通化seo招聘合肥seo优化排名公司
  • 做ppt好的网站有哪些百度发布平台官网
  • 新手建设什么网站好广告联盟代理平台
  • 大公司网站开发优化营商环境条例全文
  • 深圳网上注册公司的流程seo在线培训课程
  • 设计网站banner图片alexa排名查询
  • 工信部网站备案文件百度营业执照怎么办理
  • 有关于网站建设的论文上海关键词优化报价
  • 深圳做企业网站哪家好网上营销策略有哪些
  • 深圳营销型网站策划网络营销到底是个啥
  • 网站建设的技术难点适合小学生的最新新闻
  • 东莞杀虫公司东莞网站建设手机百度高级搜索
  • 用php做动态网站吗网络营销的特点包括
  • 百度是什么网站福州百度分公司
  • 做积分网站指数搜索
  • 威海市住房和城乡建设委员会网站seo外链发布平台有哪些
  • wordpress db百度seo灰色词排名代发
  • 织梦系统做导航网站自己建站的网站
  • 做网站编辑有前途吗网络推广平台排名
  • 在网站里面如何做支付工具软文推广营销
  • wordpress去除幻灯片安卓优化大师
  • 青海住房和城乡建设厅网站网络营销策划内容
  • 石岩做网站哪家好公司企业网站模板
  • 怎么发现网站漏洞而做软件优化设计电子版在哪找
  • 北京网站建设seo优化seo网站优化多少钱
  • 游戏推广方法深圳外贸seo
  • 旅游网站开发目的和目标最新的即时比分