尊重原创: http://blog.csdn.net/sk719887916/article/details/48464035

上篇《Android View 中invalidate()
你所不知道的那些事
》主要了解了view重绘的整个流程,通过从源码的学习大家了解了view整个invalidate的整个流程,但是上篇中view的另一个重要方法 requestLayout()没做细说,本篇继续分析requestLayout()。

上文中细说了从view.invalidate()开始到view.draw()的整个过程,当然今天也从view.requestLayout()开始分析起。

requestLayout过程

顾名思义,本代码从方法名字理解为请求布局,此方法主要是将本view重新布局 ,然后绘制。当我们从某个view中调用 view.requestLayout()时,会触发super的requestLayout(),也就是整个View的invalidate(),经过判断后响应ViewParent的requestLayout(),接着获取ViewRootImpl实列调用其本身的requestLayout()
,通过执行scheduleTraversals();发送消息 ,然后ViewRoot的hander处理performTraversals(),从而做出重绘draw()动作 ,,最终还是和invalidate()执行到同一个方法上,现在我就从源码分析起

1  TextView.requestLayout()

具体某个控件 可以调用此方法,则可以让本View重新走一边测量,布局,以及绘制流程,他会调用父类的(也就是View)的requestLayout()方法,可以看下如下代码 (EP1),代码逻辑也不复杂,只要是清空测量好的数据,接着重新设置下view的AttachInfo,然后最后调用Parent的requsetLayout(),把请求权交给ViewGroup处理,

而ViewGroup呢 会得到我们的View的控制核心ViewRoot,用他的实现类ViewRootImpl去重新requestLayout()。

EP1:

 public void requestLayout() {
        if (mMeasureCache != null) mMeasureCache.clear();

        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
            // Only trigger request-during-layout logic if this is the view requesting it,
            // not the views in its parent hierarchy
            ViewRootImpl viewRoot = getViewRootImpl();
            if (viewRoot != null && viewRoot.isInLayout()) {
                if (!viewRoot.requestLayoutDuringLayout(this)) {
                    return;
                }
            }
            mAttachInfo.mViewRequestingLayout = this;
        }

        mPrivateFlags |= PFLAG_FORCE_LAYOUT;
        mPrivateFlags |= PFLAG_INVALIDATED;

        if (mParent != null && !mParent.isLayoutRequested()) {
            mParent.requestLayout();
        }
        if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
            mAttachInfo.mViewRequestingLayout = null;
        }
    }

当然这种请求就是一种递归的过程, 在上面的mParent.requestLayout()其实他只是个接口,最终还是由View重载实现,还是回到上面的方法中,当ViewRoot已经请求过了,标记为不再请求布局时,才会return,可见上面的 第八行代码。

2 ViewRoot. requestLayout()

当View把控制权交由ViewRoot后,ViewRoot就会调用自己的requestLayout(),代码如下 (EP2),首先会检测修改UI的线程是否是UI主线程,当然这个代码在上篇的文章中已经说过,子线程无法更改UI的异常就是从 checkThread()里面抛出来的,接着讲本此操作标记为已经请求过,后调用 scheduleTraversals()发送消息给我们的viewRoot处理消息。

EP2:

/**
     * {@inheritDoc}
     */
    public void requestLayout() {
        checkThread();
        mLayoutRequested = true;
        scheduleTraversals();
    }

3   scheduleTraversals( )

从上篇文章大家都知道ViewRoot本省就是handler的子类,本身就可以发送消息和处理消息,我们再来看下scheduleTraversals()(EP3),方法内部很简单,标记为已经发送了该消息,然后sendMeasse,带的参数也就是说明要执行Traversals()了,那么我再继续看看在哪里去处理这条消息的呢,

EP3:

  public void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            sendEmptyMessage(DO_TRAVERSAL);
        }
    }

4 performTraversals( )

接着找到在handleMessage中处理了此消息,下面代码(Ep4)中的第二个case,就会处理我们请求执行的地方,发现也是和invalidate()执行一样的结果,在这里估计你也知道了,其实invalidfate()和resquestLayout()最终都会被ViewRoot在performTraversals()去处理,而这方法在 上篇《Android
View 中invalidate() 你所不知道的那些事
》 中做了细说,最后还是会调用我们需要view注入进去的那个view的draw()函数,比如就是上文中TextView的darw()的方法, 这让我们更见确信Android中的view都是从子节点绘制逐步网上层递归的规程,然而开发的时候确实从父节点开始布局的,但是这不是互相矛盾的。当我代码加入一个view时,他不会先对View所在的viewGruop做准备工作,而是先对这个view进行处理,不管是measure,还是layout,都是一样的原理,直到我们的根节点被标记完所有子节点都进行完了测量,布局,绘制后
ViewRoot才会回调当前界面的view全部绘制结束,

EP4:

@Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case View.AttachInfo.INVALIDATE_MSG:
            ((View) msg.obj).invalidate();
            break;
        case View.AttachInfo.INVALIDATE_RECT_MSG:
            final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
            info.target.invalidate(info.left, info.top, info.right, info.bottom);
            info.release();
            break;
        case DO_TRAVERSAL:
            if (mProfile) {
                Debug.startMethodTracing("ViewRoot");
            }

            performTraversals();

            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
            break;
        case FINISHED_EVENT:
            handleFinishedEvent(msg.arg1, msg.arg2 != 0);
            break;

在performTraversals()的方法最后也会发现 如下代码,告知我们的window,此view已经全部绘制完毕。

             sWindowSession.finishDrawing(mWindow);

总结:

看了两篇,终于可以做总结了,还是很多疑问没有解开,那到底invalidate()和requestLayout()有什么区别,当我们通过源码分析得出不管哪个方法都会执行draw(),那么上篇中我也做了细说invalidate(),invalidate()也会执行我们的onmeasure(),layout(),draw(),但是它和resquestLayout()的不同之处,他不会清空我们测量的缓存数据,当然也不会重新回调measure,但是他会重新走Layout()过程,最终他们的目的都是重新绘制view,但是细微区别,一个要进行重新测量,一个无需进行测量。

Android ViewManager解读之requestLayout() 详解的更多相关文章

  1. Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)

    Android XML shape 标签使用详解   一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...

  2. Android图片缓存之Bitmap详解

    前言: 最近准备研究一下图片缓存框架,基于这个想法觉得还是先了解有关图片缓存的基础知识,今天重点学习一下Bitmap.BitmapFactory这两个类. 图片缓存相关博客地址: Android图片缓 ...

  3. Android Design Support Library使用详解

    Android Design Support Library使用详解 Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的And ...

  4. Android 之窗口小部件详解--App Widget

    Android 之窗口小部件详解--App Widget  版本号 说明 作者 日期  1.0  添加App Widge介绍和示例  Sky Wang 2013/06/27        1 App ...

  5. Android不规则点击区域详解

    Android不规则点击区域详解 摘要 今天要和大家分享的是Android不规则点击区域,准确说是在视觉上不规则的图像点击响应区域分发. 其实这个问题比较简单,对于很多人来说根本不值得做为一篇博文写出 ...

  6. [Android新手区] SQLite 操作详解--SQL语法

    该文章完全摘自转自:北大青鸟[Android新手区] SQLite 操作详解--SQL语法  :http://home.bdqn.cn/thread-49363-1-1.html SQLite库可以解 ...

  7. Android中Service的使用详解和注意点(LocalService)

    Android中Service的使用详解和注意点(LocalService) 原文地址 开始,先稍稍讲一点android中Service的概念和用途吧~ Service分为本地服务(LocalServ ...

  8. Android中SurfaceView的使用详解

    Android中SurfaceView的使用详解 http://blog.csdn.net/listening_music/article/details/6860786 Android NDK开发 ...

  9. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

随机推荐

  1. Hadoop加速器GridGain

    GridGain的Hadoop加速器 像GridGain等内存网格产品(IMDG)不仅可以作为简单的缓存,加速Hadoop中MapReduce计算也是IMDG的一个亮点.这样内存计算领域又多了一种思路 ...

  2. User-Agent-Switcher和fiddler

    浏览器模拟器(可以模拟各种浏览器效果,浏览器中看手机显示的效果) http://chromecj.com/web-development/2014-09/70.html User-Agent-Swit ...

  3. Spark:聚类算法之LDA主题模型算法

    http://blog.csdn.net/pipisorry/article/details/52912179 Spark上实现LDA原理 LDA主题模型算法 [主题模型TopicModel:隐含狄利 ...

  4. C++:如何删除string对象的末尾非数字字符

    功能实现: 现有一个string对象包含数字字符以及非数字字符,实现删除string对象的末尾非数字字符. 实例: 输入为"0 1 1 2 3    " 输出为"0 1 ...

  5. Linux proc/pid/task/tid/stat文件详解

    [root@localhost ~]# cat /proc/6873/stat6873 (a.out) R 6723 6873 6723 34819 6873 8388608 77 0 0 0 419 ...

  6. iOS中使用iCloud一些需要注意的地方(Xcode7.2)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在自己的App中如何使用iCloud有很多文章可以查阅,这里把 ...

  7. 如何查看App provision profile文件中的钥匙链访问组名称

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们因为某些原因希望安全的在多个App中共享一些信息,我们可以 ...

  8. 1.使用C++封装一个链表类LinkList

     使用C++封装一个链表类LinkList.写出相应一个测试用例 链表需要提供 添加 修改删除 除重 合并 排序创建 销毁等接口. 不能调用库函数或者使用STL等类库 题目延伸********** ...

  9. Java基础---Java---网络编程---TCP、UDP、UDP-键盘录入方式数据、Socket、TCP复制文件、UDP-聊天

    网络编程 网络模型 *OSI参考模型 *Tcp/IP参考模型 网络通读要素 *IP地址 *端口号 *传输协议 1.找到对方Ip 2.数据要发送到对方指定的的应用程序上,为了标识这些应用程序,所经给这些 ...

  10. Android初级教程获取手机位置信息GPS与动态获取最佳方式

    简单介绍一下gps定位的操作. 主要是靠locationmanger这个api完成的一些操作:通过获取这个实例,然后调用它的requestLocationUpdates方法进行注册.传入的参数分别有以 ...