当前位置:网站首页>view的绘制机制(一)
view的绘制机制(一)
2022-07-02 06:25:00 【android_Mr_夏】
简介
我们在学习android的时候,直接在xml中指定android的标签,就能显现出各式各样的界面,但是我们并不了解其中的绘制流程,从而抱着一个学习的心态,从源码角度去查看view的绘制机制。
目录
1.view的绘制流程(一)
2.总结
view的绘制流程
在进行分析之前,我们可以先看看下面的流程图:
每个Activity都持有Window的对象,Android 为 Window 提供了唯一的实现类 PhoneWindow。PhoneWindow 终究是 Window,它并不具备多少 View 相关的能力,不过 PhoneWindow 中持有一个 Android 中非常重要的一个 View 对象 Decor(装饰)View,它在 PhoneWindow 中的定义如下:
public class PhoneWindow extends Window{
// 最顶级view的节点,起到一个window装饰的根组件
private DecorView mDecor;
}
查看 DecorView 继承关系得知,DecorView 继承自 FrameLayout。
public class DecorView extends FrameLayout {
}
其中DecorView 的子view是一个LinerLayout布局包含TitleView和ContentView,ContentView的子布局就是FrameLayout。我们平常在Activity中的onCreate()方法中,setContentView(int layoutResID)所传入的布局就是影响着ContentView。
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
. . .
}
其中getWindow()就是PhoneWindow对象,其中的setContentView()方法,源码如下:
@Override
public void setContentView(int layoutResID) {
// mContentParent即为上面提到的ContentView的父容器,若为空则调用installDecor()生成
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
// 具有FEATURE_CONTENT_TRANSITIONS特性表示开启了Transition
// mContentParent不为null,则移除decorView的所有子View
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
// 一般情况会来到这里,调用mLayoutInflater.inflate()方法来填充布局
mLayoutInflater.inflate(layoutResID, mContentParent);
}
. . .
// cb即为该Window所关联的Activity
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
// 调用onContentChanged()回调方法通知Activity窗口内容发生了改变
cb.onContentChanged();
}
. . .
}
我们主要看mLayoutInflater.inflate(layoutResID, mContentParent):
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
. . .
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
mConstructorArgs[0] = mContext;
View result = root;
try {
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
}
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
final String name = parser.getName();
if (TAG_MERGE.equals(name)) {
if (root == null || !attachToRoot) {
throw new InflateException("merge can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, attrs);
} else {
View temp = createViewFromTag(name, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
rInflate(parser, temp, attrs);
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (IOException e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
}
return result;
}
}
从这里我们就可以清楚地看出,LayoutInflater其实就是使用Android提供的pull解析方式来解析布局文件的。我们可以注意到createViewFromTag()这个方法,把节点名和参数传了进去。看到这个方法名,我们就应该能猜到,它是用于根据节点名来创建View对象的。在createViewFromTag()方法的内部又会去调用createView()方法,然后使用反射的方式创建出View的实例并返回。
这样我们就把view的根节点给创建出来了接下来我们继续查看rInflate(parser, temp, attrs):
private void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs)
throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else {
final View view = createViewFromTag(name, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflate(parser, view, attrs);
viewGroup.addView(view, params);
}
}
parent.onFinishInflate();
}
总结
可以看到,同样是createViewFromTag()方法来创建View的实例,然后递归调用rInflate()方法来查找这个View下的子元素,每次递归完成后则将这个View添加到父布局当中。这样整个布局文件都解析完成后就形成了一个完整的DOM结构,最终会把最顶层的根布局返回,至此inflate()过程全部结束。
我们继续学习view的绘制机制(二)
边栏推荐
- php中计算两个日期之前相差多少天、月、年
- Review of reflection topics
- Tool grass welfare post
- Sqli-labs customs clearance (less15-less17)
- Oracle APEX 21.2 installation et déploiement en une seule touche
- Explain in detail the process of realizing Chinese text classification by CNN
- SQL injection closure judgment
- Explanation of suffix of Oracle EBS standard table
- Sqli labs customs clearance summary-page2
- 2021-07-19C#CAD二次开发创建多线段
猜你喜欢
Yolov5 practice: teach object detection by hand
ssm垃圾分类管理系统
Explanation and application of annotation and reflection
Changes in foreign currency bookkeeping and revaluation general ledger balance table (Part 2)
软件开发模式之敏捷开发(scrum)
ORACLE EBS中消息队列fnd_msg_pub、fnd_message在PL/SQL中的应用
Only the background of famous universities and factories can programmers have a way out? Netizen: two, big factory background is OK
Ingress Controller 0.47.0的Yaml文件
Sqli-labs customs clearance (less18-less20)
Ceaspectuss shipping company shipping artificial intelligence products, anytime, anywhere container inspection and reporting to achieve cloud yard, shipping company intelligent digital container contr
随机推荐
MySQL中的正则表达式
离线数仓和bi开发的实践和思考
Brief analysis of PHP session principle
sqli-labs通关汇总-page2
2021-07-19C#CAD二次开发创建多线段
CAD二次开发 对象
Changes in foreign currency bookkeeping and revaluation general ledger balance table (Part 2)
Sqli-labs customs clearance (less15-less17)
SQL注入闭合判断
User login function: simple but difficult
Flex Jiugongge layout
读《敏捷整洁之道:回归本源》后感
ORACLE 11G利用 ORDS+pljson来实现json_table 效果
Oracle 11g uses ords+pljson to implement JSON_ Table effect
php中时间戳转换为毫秒以及格式化时间
Data warehouse model fact table model design
ORACLE EBS中消息队列fnd_msg_pub、fnd_message在PL/SQL中的应用
软件开发模式之敏捷开发(scrum)
SQLI-LABS通关(less1)
php中判断版本号是否连续