Android-举一反三:12个View绘制流程高频面试题,带你全面理解View的绘制流程

本文详细探讨了Android中View的绘制流程,从LayoutInflater的Factory接口到ViewRootImpl的measure、layout和draw过程,解释了requestLayout和invalidate的区别。通过分析Activity、PhoneWindow、DecorView和ViewRootImpl的关系,揭示了触发重新绘制的方法。文中强调理解这些知识点对于Android开发者在面试和实际工作中的重要性,并鼓励读者深入学习和交流。
摘要由CSDN通过智能技术生成

mFactory = mFactory2 = new FactoryMerger(factory, factory, mFactory, mFactory2);

}

}

private static class FactoryMerger implements Factory2 {

private final Factory mF1, mF2;

private final Factory2 mF12, mF22;

FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) {

mF1 = f1;

mF2 = f2;

mF12 = f12;

mF22 = f22;

}

public View onCreateView(String name, Context context, AttributeSet attrs) {

View v = mF1.onCreateView(name, context, attrs);

if (v != null) return v;

return mF2.onCreateView(name, context, attrs);

}

public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {

View v = mF12 != null ? mF12.onCreateView(parent, name, context, attrs)
mF1.onCreateView(name, context, attrs);

if (v != null) return v;

return mF22 != null ? mF22.onCreateView(parent, name, context, attrs)
mF2.onCreateView(name, context, attrs);

}

}

然后我们再看 mPrivateFactory,看名称就知道是系统的隐藏方法。

调用时机是在 Activity.attach 中,Activity 其实是实现了 Factory2 的 onCreateView 方法,其中对 fragment 做了处理,如果是 fragment 标签,就调用 fragment 的 onCreateView,这里就不详细往下面看了,如果是非 fragment 的标签,就返回 null,走默认的创建 View 的方法。

/**

  • @hide for use by framework

*/

public void setPrivateFactory(Factory2 factory) {

if (mPrivateFactory == null) {

mPrivateFactory = factory;

} else {

mPrivateFactory = new FactoryMerger(factory, factory, mPrivateFactory, mPrivateFactory);

}

}

// Activity

final void attach(…)

mWindow.getLayoutInflater().setPrivateFactory(this);

}

public View onCreateView(String name, Context context, AttributeSet attrs) {

return null;

}

public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {

if (!“fragment”.equals(name)) {

return onCreateView(name, context, attrs);

}

return mFragments.onCreateView(parent, name, context, attrs);

}

所以上面的 Factory 和 Factory2,是系统留给我们的 hook View 创建流程的接口。

如果都没有设置,那就走到默认的创建 View 的方法。

默认创建 View 的方法比较简单,就是反射调用 View 的构造函数,然后做一个缓存,然后创建 View。

具体代码如下

// LayoutInflate

View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,

boolean ignoreThemeAttr) {

// 前面的 mFactory、mFactory2、mPrivateFactory 都没有去创建 View

if (view == null) {

final Object lastContext = mConstructorArgs[0];

mConstructorArgs[0] = context;

try {

if (-1 == name.indexOf(‘.’)) {

// 如果名称里没有 “.”,也就是系统的 View,需要添加 android.view. 前缀,比如 ,最终去创建的名称是 android.view.LinearLayout

view = onCreateView(parent, name, attrs);

} else {

// 如果是自定义 View,则直接去创建

view = createView(name, null, attrs);

}

} finally {

mConstructorArgs[0] = lastContext;

}

}

// …

}

protected View onCreateView(String name, AttributeSet attrs)

throws ClassNotFoundException {

return createView(name, “android.view.”, attrs);

}

public final View createView(String name, String prefix, AttributeSet attrs)

throws ClassNotFoundException, InflateException {

Constructor<? extends View> constructor = sConstructorMap.get(name);

if (constructor != null && !verifyClassLoader(constructor)) {

constructor = null;

sConstructorMap.remove(name);

}

Class<? extends View> clazz = null;

try {

if (constructor == null) {

// 加载对应的类

clazz = mContext.getClassLoader().loadClass(

prefix != null ? (prefix + name) : name).asSubclass(View.class);

// 反射获取构造函数

constructor = clazz.getConstructor(mConstructorSignature);

constructor.setAccessible(true);

// 做个缓存,下次直接使用,提高效率

sConstructorMap.put(name, constructor);

} else {

}

Object lastContext = mConstructorArgs[0];

if (mConstructorArgs[0] == null) {

// Fill in the context if not already within inflation.

mConstructorArgs[0] = mContext;

}

Object[] args = mConstructorArgs;

args[1] = attrs;

// 调用构造函数创建 View

final View view = constructor.newInstance(args);

if (view instance

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值