之前解决了自定义LayoutInflate问题,使用自定义的LayoutInflate.inflate可以得到插件资源。1.layout
1.LayoutInflate解析。
//当root传入null时候,attachToRoot默认传入false
414 public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
//getContext返回mContext,就是我们在构造函数传入的 为插件生成的context(里面只有插件资源)
415 final Resources res = getContext().getResources();
421 final XmlResourceParser parser = res.getLayout(resource);
423 return inflate(parser, root, attachToRoot);
427 }
接下来inflate传入解析的XmlResourceParser,逐个生成veiw
主要代码492行 createViewFromTag
451 public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
//inflaterContext就是传入的插件mContext
458 mConstructorArgs[0] = inflaterContext;
459 View result = root;
461 try {
474 final String name = parser.getName();
483 if (TAG_MERGE.equals(name)) {
489 rInflate(parser, root, inflaterContext, attrs, false);
490 } else {
491 // Temp is the root view that was found in the xml
492 final View temp = createViewFromTag(root, name, inflaterContext, attrs);
//忽略代码,设置layoutparams带有attrs到temp中
514 // Inflate all children under temp against its context.
515 rInflateChildren(parser, temp, attrs, true);
553 }
注意,创建子view时候会调用context.getTheme,获取att,所以要重写getTheme返回Android系统的theme否则会因为找不到宿主style资源而报错。
748 View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
749 boolean ignoreThemeAttr) {
//ignoreThemeAttr是false就先设置theme到context中
//如果有mPrivateFactory就调用Factory的createView
//最后应该调用这里
790 view = createView(name, null, attrs);
813 }
这里主要找到具体的类,获得构造函数,调用构造函数,传入两个args,1.mContext 。2.attrs
575
592 public final View createView(String name, String prefix, AttributeSet attrs)
593 throws ClassNotFoundException, InflateException {
594 Constructor<? extends View> constructor = sConstructorMap.get(name);
595 if (constructor != null && !verifyClassLoader(constructor)) {
596 constructor = null;
597 sConstructorMap.remove(name);
598 }
599 Class<? extends View> clazz = null;
600
601 try {
602 Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);
603
604 if (constructor == null) {
605 // Class not found in the cache, see if it's real, and try to add it
606 clazz = mContext.getClassLoader().loadClass(
607 prefix != null ? (prefix + name) : name).asSubclass(View.class);
608
609 if (mFilter != null && clazz != null) {
610 boolean allowed = mFilter.onLoadClass(clazz);
611 if (!allowed) {
612 failNotAllowed(name, prefix, attrs);
613 }
614 }
615 constructor = clazz.getConstructor(mConstructorSignature);
616 constructor.setAccessible(true);
617 sConstructorMap.put(name, constructor);
618 } else {
619 // If we have a filter, apply it to cached constructor
620 if (mFilter != null) {
621 // Have we seen this name before?
622 Boolean allowedState = mFilterMap.get(name);
623 if (allowedState == null) {
624 // New class -- remember whether it is allowed
625 clazz = mContext.getClassLoader().loadClass(
626 prefix != null ? (prefix + name) : name).asSubclass(View.class);
627
628 boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
629 mFilterMap.put(name, allowed);
630 if (!allowed) {
631 failNotAllowed(name, prefix, attrs);
632 }
633 } else if (allowedState.equals(Boolean.FALSE)) {
634 failNotAllowed(name, prefix, attrs);
635 }
636 }
637 }
638
639 Object lastContext = mConstructorArgs[0];
640 if (mConstructorArgs[0] == null) {
641 // Fill in the context if not already within inflation.
642 mConstructorArgs[0] = mContext;
643 }
644 Object[] args = mConstructorArgs;
645 args[1] = attrs;
646
647 final View view = constructor.newInstance(args);
648 if (view instanceof ViewStub) {
649 // Use the same context when inflating ViewStub later.
650 final ViewStub viewStub = (ViewStub) view;
651 viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
652 }
653 mConstructorArgs[0] = lastContext;
654 return view;
680 }
681