范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Android关于绘制的一个小细节分享

  作者:陈小缘
  很多时候我们在自定义 View 的需要做动画的时候,我们可以依赖属性动画的回调周期性修改 自定义的属性值,然后调用   invalidate    方法实现。
  不过我还见过一个比较野的路子,它在   onDraw    里面直接修改属性,然后调用 invalidate()    方法。
  运行起来好像也没问题。
  那么问题来了:  在   onDraw    里面调用 修改绘制相关属性(例如画圆,修改半径) invalidate()    ,这种与属性动画的回调调用 invalidate()   源码分析有什么区别?在   onDraw    里面调用 invalidate()    会存在什么问题?
  在View.onDraw方法里调用View.invalidate和在ValueAnimator.AnimatorUpdateListener中调用View.invalidate,有区别吗?
  了解  ValueAnimator   的同学会知道,它播放动画的实现原理并不是直接使用线程来不断计算并回调AnimatorUpdateListener   ,而是…来写代码测试下就知道了:ValueAnimator.ofInt(1).apply {     addUpdateListener {         // 因为animatedFraction=0时是直接回调的         if (it.animatedFraction > 0) {             throw RuntimeException()         }     }     start() }
  代码很简单,随便创建一个  ValueAnimator   然后在它的UpdateListener   里面去抛出一个异常。
  看看堆栈信息:  E/AndroidRuntime: FATAL EXCEPTION: main     Process: com.wuyr.wanandroidqa, PID: 16027     java.lang.RuntimeException         at com.wuyr.wanandroidqa.activities.main.TestActivity$start$1$1.onAnimationUpdate(TestActivity.kt:112)         at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1566)         at android.animation.ValueAnimator.animateBasedOnTime(ValueAnimator.java:1357)         at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1489)         at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146)         at android.animation.AnimationHandler.access$100(AnimationHandler.java:37)         //////////         //   3         //////////         at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54)         //////////         //   2         //////////         at android.view.Choreographer$CallbackRecord.run(Choreographer.java:970)         at android.view.Choreographer.doCallbacks(Choreographer.java:796)         //////////         //   1         //////////         at android.view.Choreographer.doFrame(Choreographer.java:727)         at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)         at android.os.Handler.handleCallback(Handler.java:938)         at android.os.Handler.dispatchMessage(Handler.java:99)         at android.os.Looper.loop(Looper.java:223)         at android.app.ActivityThread.main(ActivityThread.java:7656)         at java.lang.reflect.Method.invoke(Native Method)         at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
  看标记1处,来到了  Choreographer.doFrame   方法,View的绘制,各种输入/触摸事件等也是在这里开始处理的。
  接着看2,  Choreographer.java   第970行:private static final class CallbackRecord {     public Object action; // Runnable or FrameCallback      public void run(long frameTimeNanos) {             ......             ((FrameCallback)action).doFrame(frameTimeNanos); // 970行             ......     } }
  这里把action强转为  FrameCallback   ,而标记3处:public class AnimationHandler {     private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {         @Override         public void doFrame(long frameTimeNanos) {             doAnimationFrame(getProvider().getFrameTime()); // 54行             if (mAnimationCallbacks.size() > 0) {                 getProvider().postFrameCallback(this);             }         }     }; }
  可以看到它回调的正是  AnimationHandler   的mFrameCallback   。
  但是  ValueAnimator   怎么会跟AnimationHandler   扯上关系呢?
  其实在我们调用  start   方法播放动画的时候,它就已经把一个Callback添加到AnimationHandler   里面去了:public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {      @Override     public void start() {         start(false);     }      private void start(boolean playBackwards) {         ......          addAnimationCallback(0);          ......     }       private void addAnimationCallback(long delay) {         AnimationHandler.getInstance().addAnimationFrameCallback(this, delay);     }      /*         这里实现AnimationHandler.AnimationFrameCallback接口的方法     */     @Override     public final boolean doAnimationFrame(long frameTime) {         ......     } }
  这个Callback正是  ValueAnimator   自身。
  那它最终会被传到哪里呢?
  代码套那么多层就不全贴了,它最终会通过  Choreographer.postFrameCallback   方法:public final class Choreographer {      public void postFrameCallback(FrameCallback callback) {         postFrameCallbackDelayed(callback, 0);     }      public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) {         ......         postCallbackDelayedInternal(CALLBACK_ANIMATION,                 callback, FRAME_CALLBACK_TOKEN, delayMillis);     } }
  传到了  Choreographer   中。
  可以看到它最后调用的是  postCallbackDelayedInternal   方法,记住!这个很重要!
  好,回到主题。
  通过刚刚一段分析,可以知道,  ValueAnimator.AnimatorUpdateListener   ,是在Choreographer.doFrame   回调时才回调的。也就是说,ValueAnimator   开始后,AnimatorUpdateListener   会在每一次屏幕刷新的时候回调!
  还有一个区别就是,动画进度计算方式不同,  ValueAnimator   是根据记录的开始时间来计算的,所以它不会受到Activity生命周期或其他因素影响。而直接在onDraw   里回调的就不同了,如果动画在播放过程中Activity Stopped了,onDraw   就会暂停回调,那么下一次的invalidate时间,也就无从确定了。不过,可能刚好有这样的需求,需要在Activity不可见时暂停动画呢?
  在View.onDraw中直接调用invalidate方法会有什么问题?
  看了  @xujiafeng  同学的回答,他说这样做的话,  IdleHandler   不会被回调。公众号文章在这里:Android 避坑指南:实际经历来说说IdleHandler的坑
  emmmm,其实我觉得这不应该是一个问题,因为Handler的机制就是这样的啊,  MessageQueue   还有事情没处理完,肯定不会告诉你说它有空啦。
  等动画播放完毕,  IdleHandler   还是会正常回调的。
  不过你说是要无限循环播放的话,让  MessageQueue   一直忙碌,导致IdleHandler   一直没能被回调的话,那确实是个问题,就拿常见的场景来说:每日一问 | Activity 调用了finish()方法会立即调用onDestory()吗? ,Activity的Destory   也是依赖IdleHandler   来完成的(虽然有超时机制)。(以后会跟大家一起debug AMS来详细分析这个问题)
  https://www.wanandroid.com/wenda/show/13244
  如果真的有这样的需求,除了改用  ValueAnimator   之外,就没其他方法了吗?
  肯定有啦,你想想  ScrollView   、RecyclerView   、ViewPager   等等这些View的惯性滚动动画效果是怎么做的?
  它们其实是通过一个叫  postInvalidateOnAnimation   的方法来invalidate   的,关于这个方法,我记得在前面好几个回答都提到过了。
  来看下它原理是怎么样的吧:
  长话短说,它最终是调用  Choreographer.postCallback   方法来把一个会调用View.invalidate   的Runnable   传进去:public final class Choreographer {     public void postCallback(int callbackType, Runnable action, Object token) {         postCallbackDelayed(callbackType, action, token, 0);     }      public void postCallbackDelayed(int callbackType, Runnable action, Object token, long delayMillis) {         ......         postCallbackDelayedInternal(callbackType, action, token, delayMillis);     } }
  !!!!!看到了没?!它最终调用的是  postCallbackDelayedInternal   方法!还记得刚刚分析ValueAnimator   的时候,叫记住的那个方法吗?就是它啊!
  这就说明了,使用  View.postInvalidateOnAnimation   方法,跟在ValueAnimator.AnimatorUpdateListener   中调用invalidate   ,效果是一样的!
  同样是调用invalidate方法,为什么在AnimatorUpdateListener.onAnimationUpdate里面调用,就不会阻止IdleHandler回调呢?
  看图就明白了,这是在  onDraw   里调用invalidate   的流程:
  就算MQ里没有其他的msg,在每次Traversal任务即将处理完毕时又向MQ塞入了新的msg,所谓一波未平,一波又起,这样的话,  IdleHandler   肯定没机会回调了。
  来看下在  AnimatorUpdateListener   中调用invalidate   的流程:
  因为  AnimatorUpdateListener   的onAnimationUpdate   方法是每次屏幕刷新时才回调的,也就是大概16ms左右,在这16ms的间隔内,Looper可能已经把MQ里剩下的msg都取出来了,所以如果在AnimatorUpdateListener   里调用invalidate   的话,会看到这样的log:onAnimationUpdate: invoked onAnimationUpdate: invoked onDraw: invoked queueIdle: invoked onAnimationUpdate: invoked onDraw: invoked queueIdle: invoked onAnimationUpdate: invoked onDraw: invoked queueIdle: invoked onAnimationUpdate: invoked onDraw: invoked queueIdle: invoked onAnimationUpdate: invoked onDraw: invoked queueIdle: invoked最后
  在这里还分享一份由大佬亲自收录整理的学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料
  这些都是我现在闲暇时还会反复翻阅的精品资料。里面对近几年的大厂面试高频知识点都有详细的讲解。相信可以有效地帮助大家掌握知识、理解原理,帮助大家在未来取得一份不错的答卷。
  当然,你也可以拿去查漏补缺,提升自身的竞争力。
  真心希望可以帮助到大家,Android路漫漫,共勉!
  如果你有需要的话,只需私信我【进阶】即可获取

上市三个月降到2329元,12GB256GB4nm芯片,外观致敬苹果也不知道从什么时候起,在外观设计上一向比较保守的苹果,竟然成为了行业致敬的对象?比如当年的iPhoneX,首次在手机中使用了刘海屏,结果安卓厂商一时间全都模仿了起来。再比如今年iP新年首次油价调整上调开启,加满一箱92号汽油将多花10元!多地仍处七元时代金融界1月3日消息2023年的首次油价调整日,成品油零售限价今夜24时将开启新年第1次上调,去年底开启的三连降也就此终止。据国家发改委今日消息,根据近期国际市场油价变化情况,按照现一加11和iQOO11谁更香?新年入手先别急,这些差异建议看一看最近一个多月时间,手机圈已经发布了超过10款骁龙8Gen2机型,加上1月4日发布的一加11,一共是11款。这些机型各有各的看点,有主打影像的vivoX90系列有主打手感和续航体验的新年新旅游丨极边第一城,腾冲冬日生活打卡季300年前,明代著名地理学家徐霞客,越过崇山峻岭,跨过大江大河,来到西南边陲腾冲,被此地的美丽和繁华所震撼,留下了极边第一城的称赞。300年后,腾冲虽以胡焕庸线的端点12月小麦价格跌后小幅回涨1月上旬行情或难好转导语12月中上旬,厂家面粉走货偏慢,开工率处低位,小麦采购热情不高,同时产区交通运输恢复,小麦货源流通更加便利,价格行情走低。下旬部分厂家面粉订单量略增,小麦采购意向稍有增强,低价差距有这么大?OPPO华为三星折叠旗舰对比,结果很意外智能手机行业发展了这么多年,说实话已经是有点性能过剩的味道了,除了需要玩一些大型游戏,又或者是用手机修图什么的,以目前的性能配置来讲,只要是旗舰机,流畅用个23年是完全没问题的。所一加11领衔2023年值得买的旗舰手机三星和小米同样值得期待如何在2023年挑选一款适合自己的旗舰手机?对于这个问题其实目前来说还是比较困难的,因为接下来将会有很多品牌陆续推出自己的新款旗舰,对于消费者用户来说如果不知道它们的特性,很难买到这3种天然青霉素食物,隔三差五吃一次,身体健康过一冬在寒冷的冬季,病菌的繁殖和传播速度都加快了,特别是现今这个特殊时期,更不容大家松懈,外部的防护和消杀不能忘。为了抵御疾病,大家不仅要多加运动,适当多吃一些能增强抵抗力的食物也是很有库克良心发现!iPhone15标准版Plus版价格或下调,想刺激销量?要说今年的iPhone14iPhone14Plus,价格都是相对较高的主要原因还是这两款机器采用的是上代处理器,并且没有高刷新率屏幕的加持,5999元和6999元的起步价对这个配置提前4个月交房交证!澳海用实力诠释满分交付!浪潮退去,方知谁是强者。近年,在政策资金的双重压力下,部分房企亮起红灯,深陷兑现风波。于是,越是在楼市的逆境之中,越是能看出一个楼盘的秉性与品格。谁能在躺平一片的楼市中昂首前行实力斩获销售ampampamp销量额双冠天鹅奖双奖,全能旗舰红魔8Pro系列再开售最近可谓是新机发布大热潮了,各家品牌都赶在春节前发布新机。但真要论哪部机器热度最高,那真就只能是红魔8Pro系列。新机发布前可能很多人都没想到红魔8Pro系列直接从机海中杀出重围脱
写实风模拟经营动物收容所上架Steam!支持简中由GamesIncubator开发的模拟经营类游戏动物收容所(AnimalShelter)现已上架Steam。(点此前往Steam商店页)本作是一款动物救助站模拟游戏,游戏中玩家将永恒沉默天影传奇天影沉默2超快攻速超高爆率满屏光柱哈喽!大家好,我是你们的老朋友游戏君。今天主要给大家说说天影沉默2这款游戏,话不多说咱们直接进入正题。1神器随意搭配传奇手游中,神器一直都是令人望尘莫及的存在,然而天影沉默2却能给(第四十八期)强势的法伤英雄系列上一期刚说完,法伤的重要性,这期再直观的展示一下法伤和物伤的差距。首先说明一下,挨打的木桩,出的是这套坦克万能装备,人物选择的是卤蛋。(这套装适用全部英雄,最后一件霸者根据阵容决定E宝圣诞15连白嫖第十二弹秘奥法师昨天E宝送的是控制,依据手势的图标提示猜中!昨天根据法杖的图标猜测,送的是秘奥法师,今天也是完美猜中。所以,来介绍一下今天的秘奥法师吧。秘奥法师是一款低模风格的冒险游戏。所谓低模风Epic圣诞每日喜加一更新免费领取胡闹搬家Epic游戏商城圣诞促销季15天每日喜加一活动已进入第13天,今日的免费领取游戏是胡闹搬家(MovingOut),免费领取时间为北京时间12月29日0点至12月30日0点。胡闹搬家KPL秋季赛狼队第二局扳平比分,阿泰果然一到八点,狼队就醒了众所周知,伴随着电子竞技行业的飞速发展,国内的手游市场也是在不断壮大,出现了各种类型的手机游戏,而说到目前热度最高,最受欢迎的一款MOBA手机游戏,在小编看来绝大多数手游爱好者们第2022宝宝取名一儿一女的绝美名字君泽君怡遗风遗泽,心旷神怡青朔青玥白齿青眉,众星捧玥若安若璎安居乐业,簪缨世胄思来思萱南来北往,椿庭萱室允初妍初允文允武,尽态极妍舒月星月云舒霞卷,灿若繁星幸川幸雨海纳百川,和风细历时三个月,昌平西关环岛完成华丽变身为将西关环岛打造为骑行驿站城市花园,昌平公路分局于去年9月下旬启动了京青线西关环岛段中修工程,并于近日顺利竣工。西关环岛连接着京藏高速京青线政府街西路西关路,是昌平城区重要的交通枢云南花费71。06亿元打造高速,全长48。198千米,预计在10月开通随着国内经济发展大幅度提升,带动了很多城市的发展也越来越好,当然这一功劳也脱不了城市自身做出的努力贡献。很多城市一直都积极发展,为了推动城市的经济体现,缩小城乡之间的经济差距,很多当从秦汉到近代的古风女孩玩起了现代的休闲娱乐现代女孩子的主要休闲娱乐活动逛街旅游美容网购追剧看直播,吃吃喝喝那古代呢?我们印象中古代的女子是需要大门不出,二门不迈的,但是从保留下来的画卷和书籍来看,古代女子的休闲生活并不局限让人饱受折磨的足跟痛是顽疾?试试这3个方法,轻松缓解疼痛老师,我脚跟疼了半年多了,时好时坏,到底咋回事?我右脚跟总是疼,特别是早晨起床下地时,疼得厉害,过一会就好多了树枯根先竭,人老脚先衰。进入冬天,我收到不少咨询足跟痛的留言,那今天就29215,26228,262111,MVP真猛!詹姆斯的无助你感受到了时间来到1月初,202122赛季NBA常规赛激战正酣。常规赛到了目前这个阶段,各队的球星们都已经开始陆续发力了。一方面是因为全明星周末日益临近,全明星阵容的投票入口即将开启,明星大西部全明星首发詹库约已板上钉钉,莫兰特保罗东契奇3选1太纠结不知不觉NBA本赛季已经开打了两个多月,赛程即将过半,下面就是热热闹闹的全明星周末了。大半年前官方早就宣布2022年全明星举办地在克利夫兰骑士队主场进行,并且全明星投票已经开启好几盘点2021世界足坛10件大事2021年已经走到了最后一天,我们一起做个全年复盘,回顾一下2021年世界足坛发生的10件大事。2021年足坛大事件之一林皇的崛起震撼指数戏剧指数林皇崛起于一个特殊的时刻。卡里乌斯再见字母哥!顶级空间型中锋正式离队,或底薪加盟湖人联手詹姆斯大家好!我们今天来聊聊考辛斯再见字母哥!顶级空间型中锋正式离队,或底薪加盟湖人联手詹姆斯。考辛斯曾经是联盟第一中锋,但在他受伤之后,状态大不如前,如今他过着流浪汉的生活,最近几个赛张镇麟是撞到了新秀墙了么?上赛季强势加盟辽篮的大公子张镇麟可谓一路顺风顺水,多年深受三号位困扰的辽篮可谓久旱逢甘雨,双方无缝连接,一拍即合。首个赛季大公子场均出场32。2分钟,砍下13。9分5。7篮板1。5场均3010猛将加盟!广东最新外援出炉,2米01得分狂人,取代马尚北京时间1月6日,据国内媒体人透露,广东男篮接近签约前CBA外援里奇莱多,这意味着广东队即将拥有双外援组合。此前里奇莱多在离开台湾省球队梦想家之后一直被传言在和一支CBA顶尖队伍谈李春江赛后大闹技术台,边解领带边回头怒骂,技术代表一言不发CBA常规赛第18轮,上海男篮以100117不敌山东男篮,而在赛后,上海主帅李春江对于裁判的部分判罚不满意,大闹技术台,气势咄咄逼人的对着临场技术代表发泄情绪,不断的质问裁判员乱吹继费舍尔后,科比老大哥福克斯为何宁愿被喷也要追求瓦妮莎?人红是非多,自从科比去世后,遗孀瓦妮莎频繁登上热搜,原因很简单,那就是有太多人被曝出想追求瓦妮莎,另外瓦妮莎还经常和一些陌生男子拍摄亲密合照,甚至有过分动作,种种行为表明,不怨球迷8位港台过气明星,有人当服务员,有人疾病缠身,有人夜总会谋生娱乐圈里,更新迭代的速度非常之快。就算此刻能够火遍全球的艺人,也不敢保证自己能炙手可热一辈子。这次,八姑姑就给大家盘点8位港台过气明星的现状,看看那些曾经备受追捧的艺人,现在正经历综艺一哥李彬消失的真相曾经的快乐大本营有多火?贝克汉姆LadyGaga的综艺首秀都给了快乐大本营。但就是这样一个盘踞几十年的综艺节目,却甘愿在一档节目面前低头。这档节目就是超级大赢家,是安徽卫视推出的综小S的九个预言此文为高能E蓓子原创,禁止任何形式的转载,转载请后台联系,但欢迎你们转发到朋友圈。台剧华灯初上第2季上架了,大概是受王力宏李靓蕾婚变事件冲击,徐若瑄戏份极少,仅出现在阿季谢琼煖的回