[Android framework学习] ViewGroup的addView函数分析
博客首页:http://www.cnblogs.com/kezhuang/p/
Android中整个的View的组装是采用组合模式。
ViewGroup就相当与树根,各种Layout就相当于枝干,各种子View,就相当于树叶。
至于View类。我们就当它是个种子吧。哈哈!
ViewGroup属于树根,可以生长数很多枝干(继承自定义Layout)而枝干上有可以长出很多叶子(TextView,ImageVIew......)
好,闲话少叙,接下来步入正题!
首先,关于View的操作方法,被定义在一个叫做ViewManager的接口中,接口中还有两个方法,分别是移除和更新,这次主要分析addView
public interface ViewManager
{
/**
* Assign the passed LayoutParams to the passed View and add the view to the window.
* <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
* errors, such as adding a second view to a window without removing the first view.
* <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
* secondary {@link Display} and the specified display can't be found
* (see {@link android.app.Presentation}).
* @param view The view to be added to this window.
* @param params The LayoutParams to assign to view.
*/
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view)
}
addView在ViewGroup中实现,接下来贴出代码进行分析
public void addView(View child, LayoutParams params) {
addView(child, -1, params);
}
这个方法中调用了自身的addView方法,并且多传递了一个-1,这个-1是View的索引,要插入的位置
public void addView(View child, int index, LayoutParams params) {
if (DBG) {
System.out.println(this + " addView");
}
if (child == null) {
throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
}
// addViewInner() will call child.requestLayout() when setting the new LayoutParams
// therefore, we call requestLayout() on ourselves before, so that the child's request
// will be blocked at our level
requestLayout();
invalidate(true);
addViewInner(child, index, params, false);
}
这个方法先是重绘了一下布局,然后调用了addViewInner(child, index, params, false);方法,来把View插入到相应的位置
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
if (mTransition != null) {
// Don't prevent other add transitions from completing, but cancel remove
// transitions to let them complete the process before we add to the container
mTransition.cancel(LayoutTransition.DISAPPEARING);
}
if (child.getParent() != null) {
throw new IllegalStateException("The specified child already has a parent. " +
"You must call removeView() on the child's parent first.");
}
if (mTransition != null) {
mTransition.addChild(this, child);
}
if (!checkLayoutParams(params)) {
params = generateLayoutParams(params);
}
if (preventRequestLayout) {
child.mLayoutParams = params;
} else {
child.setLayoutParams(params);
}
if (index < 0) {
index = mChildrenCount;
}
//ViewGroup用一个View类型的数组去维护下边的子view,这个方法就是把view添加到响应的位置上
addInArray(child, index);
//绑定插入的view的父容器为当前group
// tell our children
if (preventRequestLayout) {
child.assignParent(this);
} else {
child.mParent = this;
}
if (child.hasFocus()) {
requestChildFocus(child, child.findFocus());
}
AttachInfo ai = mAttachInfo;
if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
boolean lastKeepOn = ai.mKeepScreenOn;
ai.mKeepScreenOn = false;
child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
if (ai.mKeepScreenOn) {
needGlobalAttributesUpdate(true);
}
ai.mKeepScreenOn = lastKeepOn;
}
if (child.isLayoutDirectionInherited()) {
child.resetRtlProperties();
}
dispatchViewAdded(child);
if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
}
if (child.hasTransientState()) {
childHasTransientStateChanged(child, true);
}
if (child.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
if (mTransientIndices != null) {
final int transientCount = mTransientIndices.size();
for (int i = 0; i < transientCount; ++i) {
final int oldIndex = mTransientIndices.get(i);
if (index <= oldIndex) {
mTransientIndices.set(i, oldIndex + 1);
}
}
}
}
这个方法先检查一下LayoutParams,看看插入的该view是否存在长宽,如果没有就生成一个默认的LayoutParams
然后判断index是否小于0,小于0就赋值为当前容器中的个数,代表插入到最后一项
随后就调用addInArray方法,来插入View到当前ViewGroup中,插入完成后给该view绑定一下父容器(getParent的值)
随后就是一些焦点,监听的分发,我们仔细分析一下插入方法就好了,就是addInArray
private void addInArray(View child, int index) {
View[] children = mChildren;
final int count = mChildrenCount;
final int size = children.length;
if (index == count) {
if (size == count) {
mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
System.arraycopy(children, 0, mChildren, 0, size);
children = mChildren;
}
children[mChildrenCount++] = child;
} else if (index < count) {
if (size == count) {
mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
System.arraycopy(children, 0, mChildren, 0, index);
System.arraycopy(children, index, mChildren, index + 1, count - index);
children = mChildren;
} else {
System.arraycopy(children, index, children, index + 1, count - index);
}
children[index] = child;
mChildrenCount++;
if (mLastTouchDownIndex >= index) {
mLastTouchDownIndex++;
}
} else {
throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
}
}
mChildren是ViewGroup中的一个View类型的数组,里边存放了该Group下的所有子View
ARRAY_CAPACITY_INCREMENT这个常量的值是12
首先判断一下mChildren的位置还是否充足,不充足就继续扩充12个位置出来,copy源数组内容进到新数组里,然后再把本次要添加的view放到最后
如果index比count小,说明是插入操作,也是先判断位置是否充足,不充足就扩充并且copy到index处,然后在把剩下的copy到index+1到末尾
这样就把index位置空了出来。就完成了插入操作
插入完成后,系统会重绘界面,你就可以看到你插入的view了。
addView这个方法就分析完了,有什么疑问就可以指出来,错误也一样。共同学习共同进步。
[Android framework学习] ViewGroup的addView函数分析的更多相关文章
- [Android FrameWork 6.0源码学习] ViewGroup的addView函数分析
Android中整个的View的组装是采用组合模式. ViewGroup就相当与树根,各种Layout就相当于枝干,各种子View,就相当于树叶. 至于View类.我们就当它是个种子吧.哈哈! Vie ...
- Android FrameWork学习(二)Android系统源码调试
通过上一篇 Android FrameWork学习(一)Android 7.0系统源码下载\编译 我们了解了如何进行系统源码的下载和编译工作. 为了更进一步地学习跟研究 Android 系统源码,今天 ...
- Android FrameWork 学习之Android 系统源码调试
这是很久以前访问掘金的时候 无意间看到的一个关于Android的文章,作者更细心,分阶段的将学习步骤记录在自己博客中,我觉得很有用,想作为分享同时也是留下自己知识的一些欠缺收藏起来,今后做项目的时候会 ...
- Android Framework 学习和需要学习的内容
1. 之前的研究太偏向应用层功能实现了,很多原理不了解没有深究,现在研究framework面存一些资料待有空查看. 2.Android系统的层次如下: 3.项目目录简单分析如下: 4.telphony ...
- Android Framework 学习
1. 之前的研究太偏向应用层功能实现了,很多原理不了解没有深究,现在研究framework面存一些资料待有空查看. 2.Android系统的层次如下: 3.项目目录简单分析如下: 4.telphony ...
- Android 框架学习2:源码分析 EventBus 3.0 如何实现事件总线
Go beyond yourself rather than beyond others. 上篇文章 深入理解 EventBus 3.0 之使用篇 我们了解了 EventBus 的特性以及如何使用,这 ...
- Android NDK 学习之调用Java函数
本博客主要是在Ubuntu 下开发,且默认你已经安装了Eclipse,Android SDK, Android NDK, CDT插件. 在Eclipse中添加配置NDK,路径如下Eclipse-> ...
- Linux学习笔记32——select()函数分析【转】
Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如 connect.accept.recv或recvfrom这样的阻塞程序 ...
- [Android FrameWork 6.0源码学习] View的重绘过程之WindowManager的addView方法
博客首页:http://www.cnblogs.com/kezhuang/p/关于Activity的contentView的构建过程,我在我的博客中已经分析过了,不了解的可以去看一下<[Andr ...
随机推荐
- FFmpeg 结构体学习(七): AVIOContext 分析
在上文FFmpeg 结构体学习(六): AVCodecContext 分析我们学习了AVCodec结构体的相关内容.本文,我们将讲述一下AVIOContext. AVIOContext是FFMPEG管 ...
- [Swift]LeetCode386. 字典序排数 | Lexicographical Numbers
Given an integer n, return 1 - n in lexicographical order. For example, given 13, return: [1,10,11,1 ...
- [Swift]LeetCode523. 连续的子数组和 | Continuous Subarray Sum
Given a list of non-negative numbers and a target integer k, write a function to check if the array ...
- 互联网最新kafka技术面试题含答案
1.Kafka 的设计时什么样的呢? Kafka 将消息以 topic 为单位进行归纳 将向 Kafka topic 发布消息的程序成为 producers. 将预订 topics 并消费消息的程序成 ...
- ThinkPHP 数据库操作(七) : 视图查询、子查询、原生查询
视图查询 视图查询可以实现不依赖数据库视图的多表查询,并不需要数据库支持视图,例如: Db::view('User','id,name') ->view('Profile','truename, ...
- 客户端通过Feign发起请求 服务端通过request取 json对象
@RestController @RequestMapping(value = "test") public class TestServer { @RequestMapping( ...
- 规避 React 组件中的 bind(this)
React 组件中处理 onClick 类似事件绑定的时候,是需要显式给处理器绑定上下文(context)的,这一度使代码变得冗余和难看. 请看如下的示例: class App extends Com ...
- 浅谈新的布局方式-flex
引言: 网页布局在flex出来之前,是由盒模型为底子,float,position,table,百分比来进行布局的,重绘的比较多,影响性能,复杂又不好维护.flex布局,可以简便.完整.响应式地实现各 ...
- java.lang.OutOfMemoryError: unable to create new native thread问题排查以及当前系统最大进程数量
1. 问题描述 线上某应用出问题,查看日志 这一组服务器是2台,每台都有.配置为64G,使用7G,空余内存非常多 2. 问题排查 环境变化:程序迁移到新机器,新机器是CentOS 7,程序运行账号由原 ...
- 前端笔记之JavaScript(四)关于函数、作用域、闭包那点事
一.自定义函数function 函数就是功能.方法的封装.函数能够帮我们封装一段程序代码,这一段代码会具备某一项功能,函数在执行时,封装的这一段代码都会执行一次,实现某种功能.而且,函数可以多次调用. ...