Android ViewManager解读之requestLayout() 详解
尊重原创: 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() 详解的更多相关文章
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
- Android图片缓存之Bitmap详解
前言: 最近准备研究一下图片缓存框架,基于这个想法觉得还是先了解有关图片缓存的基础知识,今天重点学习一下Bitmap.BitmapFactory这两个类. 图片缓存相关博客地址: Android图片缓 ...
- Android Design Support Library使用详解
Android Design Support Library使用详解 Google在2015的IO大会上,给我们带来了更加详细的Material Design设计规范,同时,也给我们带来了全新的And ...
- Android 之窗口小部件详解--App Widget
Android 之窗口小部件详解--App Widget 版本号 说明 作者 日期 1.0 添加App Widge介绍和示例 Sky Wang 2013/06/27 1 App ...
- Android不规则点击区域详解
Android不规则点击区域详解 摘要 今天要和大家分享的是Android不规则点击区域,准确说是在视觉上不规则的图像点击响应区域分发. 其实这个问题比较简单,对于很多人来说根本不值得做为一篇博文写出 ...
- [Android新手区] SQLite 操作详解--SQL语法
该文章完全摘自转自:北大青鸟[Android新手区] SQLite 操作详解--SQL语法 :http://home.bdqn.cn/thread-49363-1-1.html SQLite库可以解 ...
- Android中Service的使用详解和注意点(LocalService)
Android中Service的使用详解和注意点(LocalService) 原文地址 开始,先稍稍讲一点android中Service的概念和用途吧~ Service分为本地服务(LocalServ ...
- Android中SurfaceView的使用详解
Android中SurfaceView的使用详解 http://blog.csdn.net/listening_music/article/details/6860786 Android NDK开发 ...
- 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高
第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...
随机推荐
- PHP Misc. 函数
PHP 杂项函数简介 我们把不属于其他类别的函数归纳到杂项函数类别. 安装 杂项函数是 PHP 核心的组成部分.无需安装即可使用这些函数. Runtime 配置 杂项函数的行为受 php.ini 文件 ...
- Python-Jupyter Notebook使用技巧
0. 体验与安装 首先可以通过Jupyter Notebook体验这个链接体验一下Jupyter Notebook. 首先安装ipython:pip3 install ipython 然后安装Jupy ...
- Latex:TexStudio的使用
http://blog.csdn.net/pipisorry/article/details/54565608 Texsdudio 快捷键 The keyboard shortcuts can be ...
- JDBC线程池创建与DBCP源码阅读
创建数据库连接是一个比较消耗性能的操作,同时在并发量较大的情况下创建过多的连接对服务器形成巨大的压力.对于资源的频繁分配﹑释放所造成的问题,使用连接池技术是一种比较好的解决方式. 在Java中,连接池 ...
- 自定义支持多行显示的RadioGroup
自定义支持多行显示的RadioGroup 原生的RadioGroup继承自LinearLayout,即只能支持一横排或者一竖排的排列显示RadioButton 现在改写RadioGroup,使它支持多 ...
- Android studio 中引用jar的其实是Maven?(二)
上一篇:Android studio 中引用jar的其实是Maven?(一) 搭建maven仓库: 去了解一个新的事物的时候,最好的方式就是去使用它.例如去了解一座城市的时候,最好的方式就是乘坐公共交 ...
- iOS 滚动视图的复用问题解决方案
LazyScroll是什么 LazyScrollView 继承自ScrollView,目标是解决异构(与TableView的同构对比)滚动视图的复用回收问题.它可以支持跨View层的复用,用易用方式来 ...
- 28 自定义View侧滑栏
ScrollMenuView.java package com.qf.sxy.customview03.widget; import android.content.Context; import a ...
- 漏洞挖局利器-Fuzz技术介绍
模糊测试的定义 模糊测试定义为"通过向应用提供非预期的输入并监控输出中的异常来发现软件中的故障(faults)的方法". 典型而言,模糊测试利用自动化或是半自动化的方法重复地向应用 ...
- EBS值集,弹性域常用表
值集 select * from fnd_flex_value_sets select * from fnd_flex_values select * from fnd_flex_valu ...