尊重原创: 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. React Native 4 for Android源码分析 一《JNI智能指针之介绍篇》

    文/ Tamic: http://blog.csdn.net/sk719887916/article/details/53455441 原文:http://blog.csdn.net/eewolf/a ...

  2. Git之(六)标签管理

    发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本.将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来.所以,标签也是版本库的一个快照 ...

  3. Programming In Scala笔记-第十七章、Scala中的集合类型

    本章主要介绍Scala中的集合类型,主要包括:Array, ListBuffer, Arraybuffer, Set, Map和Tuple. 一.序列 序列类型的对象中包含多个按顺序排列好的元素,可以 ...

  4. 【SSH系列】Hibernate映射 -- 一对多关联映射

        映射原理       一对多关联映射和多对一关联映射的映射原理是一样一样的,所以说嘛,知识都是相通的,一通百通,为什么说一对多关联映射和多对一关联映射是一样的呢?因为她们都是在多的一端加入一个 ...

  5. solr界面

    1.1 界面功能介绍 1.1.1 Analysis

  6. 剑指Offer——中国银行面试知识储备

    剑指Offer--中国银行面试知识储备+面试内容 事件介绍 时间:2016.11.23 08:30 地点:北京市海淀区永丰路299号南门(中国银行软件中心) 事件:中国银行面试(中英文面试) 注意事项 ...

  7. ROS(indigo) turtlebot2 + android一些有趣应用

    ROS和Android配合使用非常有趣,这里推荐,ROSClinet,使用rosbridge让android和ROS通信: 具体参考奥斯卡的个人剧场:http://xxhong.net/ turtle ...

  8. 20 ViewPager demo5,6:FragmentAdapter 导航数据

    Demo5 文件结构: MainActivity.java package com.qf.day20_viewpager_demo5; import java.util.ArrayList; impo ...

  9. Dynamics CRM2015 The plug-in type does not exist in the specified assembly问题的解决方法

    在用插件工具PluginProfiler调试时,报"The plug-in type  xxxx  does not exist in the specified assembly" ...

  10. mac OS X 从无法同步互联网时间想到的

    最近在mac OS X 巨浪 :)上执行 ntpdate time.nist.gov 失败,提示 13 Jan 19:41:53 ntpdate[1374]: the NTP socket is in ...