android 谈谈invalidate和postInvalidate方法的区别

【Android面试八股文】你来讲一讲invalidate() 和 postInvalicate() 的区别 当涉及到 Android 中的 View 刷新时,和都是常用的方法。 阅读详情

看这二个方法的区别只有深入到代码中去看了,首先看invalidate()方法

invalidate()分析

 public void invalidate() {
        invalidate(true);
    }

然后到

 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
            boolean fullInvalidate) {
        if (mGhostView != null) {
            mGhostView.invalidate(true);
            return;
        }

        if (skipInvalidate()) {
            return;
        }

        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
                || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
                || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
                || (fullInvalidate && isOpaque() != mLastIsOpaque)) {
            if (fullInvalidate) {
                mLastIsOpaque = isOpaque();
                mPrivateFlags &= ~PFLAG_DRAWN;
            }

            mPrivateFlags |= PFLAG_DIRTY;

            if (invalidateCache) {
                mPrivateFlags |= PFLAG_INVALIDATED;
                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
            }

            // Propagate the damage rectangle to the parent view.
            final AttachInfo ai = mAttachInfo;
            final ViewParent p = mParent;
            if (p != null && ai != null && l < r && t < b) {
                final Rect damage = ai.mTmpInvalRect;
                damage.set(l, t, r, b);
                p.invalidateChild(this, damage);
            }

            // Damage the entire projection receiver, if necessary.
            if (mBackground != null && mBackground.isProjected()) {
                final View receiver = getProjectionReceiver();
                if (receiver != null) {
                    receiver.damageInParent();
                }
            }
        }
    }

从上面的代码中有几行是关键代码:

 final ViewParent p = mParent;
            if (p != null && ai != null && l < r && t < b) {
                final Rect damage = ai.mTmpInvalRect;
                damage.set(l, t, r, b);
                p.invalidateChild(this, damage);
            }

如果了解view的绘制流程就懂这行代码

p.invalidateChild(this, damage);而p的对象是ViewParent,这个就是ViewRootImpl类了,我们再到ViewRootImpl类中找

invalidateChild方法

    @Override
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
        checkThread();
        if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);

        if (dirty == null) {
            invalidate();
            return null;
        } else if (dirty.isEmpty() && !mIsAnimating) {
            return null;
        }

        if (mCurScrollY != 0 || mTranslator != null) {
            mTempRect.set(dirty);
            dirty = mTempRect;
            if (mCurScrollY != 0) {
                dirty.offset(0, -mCurScrollY);
            }
            if (mTranslator != null) {
                mTranslator.translateRectInAppWindowToScreen(dirty);
            }
            if (mAttachInfo.mScalingRequired) {
                dirty.inset(-1, -1);
            }
        }

        invalidateRectOnScreen(dirty);

        return null;
    }

里面有一段关键代码

invalidateRectOnScreen(dirty);这个方法的第一段代码就是checkThread();
if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }

会判断这是在主线程中,现在看看scheduleTraversals()方法做了什么

void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

关键代码来了,在这里:

 mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

看看mTraversalRunnable变量,点它进入

 final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

然后才到doTraversal()中,这个如果知道view的绘制流程的话就很熟悉这个方法了

void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }
performTraversals()方法中会调用requestLayout()会对view进行重新绘制,

postInvalidate() 分析

通过源码发现会执行到这个方法

 public void postInvalidateDelayed(long delayMilliseconds) {
        // We try only with the AttachInfo because there's no point in invalidating
        // if we are not attached to our window
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
        }
    }

然后调用了ViewRootImpl类中的dispatchInvalidateDelayed() 方法

  public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
        Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
        mHandler.sendMessageDelayed(msg, delayMilliseconds);
    }

它是通过handler发送消息到主线程中去执行, 全局搜索MSG_INVALIDATE这个变量

 @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_INVALIDATE:
                    ((View) msg.obj).invalidate();
                    break;

最终跑到主线程还是调用了invalidate()方法

音频DSP开发中的‘隐藏关卡’:那些SigmaStudio未公开的模块计算秘籍 本文深入探讨音频DSP开发中SigmaStudio未公开的模块计算秘籍,重点解析动态范围控制、均衡器参数映射和混响算法优化等核心模块计算公式。通过实际案例揭示如何利用这些非官方技巧提升音频质量与系统性能,为ADI DSP开发者提供宝贵的实战经验。 阅读详情

相关推荐

最小路径和——动态规划求解(Java实现)

最小路径和——动态规划求解(Java实现) 题目: 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。 示例: 输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总和最小。 这题和机器人走路的思路类似,就是状态方程有所不同,...

weixin_43395911的博客 894

android 中的invalidate 和 postInvalidate

存在原因:android只允许在ui线程更新ui。 invalidate 在ui线程上请求更新view。比如直接在onDraw中调用; postInvalidate 用于在其他新启的线程处更新view。不需要再写handler之类,通知ui线程更新view,提供了方便。

wwwoowww的博客 308

Zynq UltraScale+ RFSoC实战:用XCZU49DR开发板实现雷达信号处理全流程

本文详细介绍了如何利用Xilinx Zynq UltraScale+ RFSoC系列中的XCZU49DR开发板,高效实现雷达信号处理全流程。文章深入剖析了该芯片集成的射频直采ADC/DAC、可编程逻辑与Arm多核处理器的异构计算优势,并通过实战案例展示了从环境搭建、硬件链路设计到软件优化的完整开发路径,为相控阵雷达等高性能应用提供了单芯片解决方案。

weixin_29291863的博客 575

Android invalidate、postInvalidate、requestLayout的区别

invalidate方法用于在UI线程中请求重绘视图。当我们希望在主线程中更新UI时,可以在UI线程中直接调用invalidate()方法。内部实现:调用了invalidate方法后,为该View添加一个标记位,同时不断向父容器请求刷新,父容器通过计算得出自身需要重绘的区域,直到传递到ViewRootImpl中,最终触发performTraversals方法,开始View树重绘流程(只绘制需要重绘的视图)

weixin_40323532的博客 1773

Anaconda详细安装及使用教程(带图文)

Anacond的介绍 Anaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。因为包含了大量的科学包,Anaconda的下载文件比较大(约531 MB),如果只需要某些包,或者需要节省带宽或存储空间,也可以使用Miniconda这个较小的发行版(仅包含conda和Python)。 Conda是一个开源的包、环境管理器,可以用于...

代码帮 186万+

process插件_利用SPSS 插件MLmed检验多水平中介的调节模型

本文介绍一个SPSS插件,用于检验多水平中介的调节,及该方法与Mplus的比较。1 Mlmed 简介及安装Mlmed 简介: Mlmed 由Rockwood 2017年开发,基于SPSS插件计算Multilevel moderated mediation. 可以提供multilevel mediation Monte Carlo 置信区间比如(模拟20000次),以及多水平调节的...

weixin_39976081的博客 5769

Android自定义View之invalidate方法和postInvalidate方法

Android自定义View系列 Android自定义View之Paint绘制文字和线 Android自定义View注意事项 Android自定义View之Canvas Android自定义View之图像的色彩处理 Android自定义View之图片外形特效——轻松实现圆角和圆形图片 Android自定义View之双缓冲机制和SurfaceView Android自定义View之Window、V...

weixin_33774308的博客 753

实用软件工程(第2版)吕云翔编简答题部分答案(自用整理)

整理自用

m0_61217768的博客 4107

Invalidate和postInvalidate的区别

在Android实际开发中,我们常常需要进行View的刷新(例如:自定义控件等),Android中为我们提供了两组刷新View的方法----Invalidate和postInvalidate,前者是在UI线程中更新View,而后者是在非UI线程中更新VIew,两组方法的具体区别如下介绍: 我们都知道,在Android中,更新UI的操作要在UI线程(也就是主线程)中进行,因为Android UI操作并

freelander_j的博客 536

SAP BSP网页开发入门:从SE80创建到MVC实战(附成品展示)

本文详细介绍了SAP BSP网页开发的入门与实战,从SE80环境搭建到MVC架构实现的全流程。通过具体案例和代码示例,帮助开发者掌握业务服务器页面(BSP)技术,提升SAP Web化转型中的开发效率,适用于需要扩展SAP功能的企业场景。

x1y2z的博客 1万+

姿态传感器/陀螺仪之SC7A20HTR是应用驱动程序设计

define SC7A20_CTRL1_PM_100HZ (0x5 << 4) // 正常模式,100Hz输出数据速率(ODR)// 用于存储6字节的原始数据(X_L, X_H, Y_L, Y_H, Z_L, Z_H)#define SC7A20_WHO_AM_I_VALUE 0x11 // 读取WHO_AM_I寄存器应该返回的值。// 但HAL_I2C_Mem_Read按顺序读,data[0]是X_L(低8位),data[1]是X_H(高8位)MX_I2C1_Init();

corlin6688的博客 757

postInvalidate和invalidate的区别

区别 相同点:都是用来更新当前的View 不同点:invalide实在UI线程中刷新View,要想在非UI线程中刷新View,就要用postInvalidate,因为postInvalidate底层是使用了Handler Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且...

ruanyandong的博客 3028

【ROS2】RViz2加载URDF模型文件

1)运行RViz2rviz22)添加组件:RobotModel3)选择通过文件添加4)选择URDF文件,此时会报错,需要修改Fixed Frame为map即可

郭老二 1450

Android面试题之View的invalidate方法和postInvalidate方法有什么区别

综上源码我们可以得出结论:(1)postInvalidate方法调用了ViewRootImpl中的dispatchInvalidateDelayed方法向ViewRootImpl中的ViewRootHandler发送一个消息,最后调用的还是View的invalidate方法。(2)因为ViewRootImpl是在UI线程的,所以postInvalidate方法的作用就是将非UI线程的刷新操作切换到UI线程,以便在UI线程中调用invalidate方法刷新View。

AntDream的程序世界 1315

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Android自定义View之invalidate和postInvalidate方法的区别

我们在自定义View时免不了要使用invalidate方法,这个方法的作用大家也比较清楚,就是让我们的View进行刷新重新绘制的。但是postInvalidate方法可能就不是那么熟悉了,因为平时开发时invalidate方法相对而言会用得比较多。不过需要大家注意的是,面试官在问到View相关的问题时,就很有可能会问到postInvalidate方法,所以我们还是有必要来学习一下。 那inval...

AntDream的程序世界 1674

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

android中Invalidate和postInvalidate的区别

转自https://www.cnblogs.com/rayray/p/3437048.html Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。 Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模...

hnlgzb的专栏 1394

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

invalidate和postInvalidate的区别及使用

invalidate和postInvalidate的区别及使用

大白 2863

Android --- android中Invalidate和postInvalidate的区别

Android中实现view的更新有两组方法,一组是invalidate,另一组是postInvalidate,其中前者是在UI线程自身中使用,而后者在非UI线程中使用。 Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。   Android程序中可以使用的界面刷新方法有两种,分别是利用Handler和利用postInval...

梁同学与Android 1036

invalidate与postinvalidate的区别

invalidate 用于进行View的刷新,在UI线程调用 postinvalidate 用于进行View的刷新,在非UI线程调用,将非UI线程切换到UI线程,最后也是调用invalidate postinvalidate源码解析 public class View implements Drawable.Callback, KeyEvent.Callback,Accessibi...

meijing11的博客 1205

Android中invalidate()和postInvalidate() 的区别

Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。  invalidate()是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。invalidate()的

小地盘的诺克萨斯 730
上一篇: android 面试题 谈谈主线程一直循环 为什么不会出现阻塞或者ANR异常
下一篇: android tint使用
zhoushenxian
博客等级 码龄12年 453粉丝 549原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值