美文网首页
Android换肤机制

Android换肤机制

作者: AndroidHint | 来源:发表于2017-09-17 01:59 被阅读0次

LayoutInflater

我们经常使用LayoutInflater将布局文件渲染成View层级视图,那么具体是怎么使用的呢?目前有四种方式:

  • context.getSystemService()
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);   
View rootView = inflater.inflate(R.layout.view_layout, null); 
  • LayoutInflater.from(context)
LayoutInflater inflater = LayoutInflater.from(context);  
View rootView = inflater.inflate(R.layout.view_layout, null); 
  • Activity下调用getLayoutInflater()
LayoutInflater inflater = getLayoutInflater();  
View rootView = inflater.inflate(R.layout.view_layout, null); 
  • View的静态方法,View.inflate()
rootView = View.inflate(context, R.layout.view_layout, null);  

通过源码可以得知,第二、第三、第四种方式其实就是第一种方式的封装,最终获取View实例的是通过inflater实例的inflate()方法。

我们再看一下Activity的onCreate()方法中的setContentView方法:

public void setContentView(int layoutResID) {
       ...省略
        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        ...省略
    }

可以看到同样也是使用了inflater的inflate()方法。所以我们可以得到这样的结论:
无论是我们自己主动调用inflater的inflate()方法渲染View,还是Activity通过setContentView来渲染View,都是通过inflater的inflate()方法来完成的。

我们继续跟踪inflate()方法,发现最终调用的是inflate(XmlPullParser,ViewGroup, boolean attachToRoot) 方法:

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            ...省略
            try {
                ...省略
                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, inflaterContext, attrs, false);
                } else {
                    // Temp is the root view that was found in the xml
                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                    ViewGroup.LayoutParams params = null;

                    if (root != null) {                     
                        // Create layout params that match root, if supplied
                        params = root.generateLayoutParams(attrs);
                        if (!attachToRoot) {
                            // Set the layout params for temp if we are not
                            // attaching. (If we are, we use addView, below)
                            temp.setLayoutParams(params);
                        }
                    }                    
                    // Inflate all children under temp against its context.
                    rInflateChildren(parser, temp, attrs, true);                   
                    ...省略
                }

            } catch (XmlPullParserException e) {
                ..省略
            } catch (Exception e) {
                ...省略
            } finally {
                ...省略            
            }
            return result;
        }
    }

我们省略掉了一些代码,直接从try代码块开始看,不考虑merge标签(其实merge标签只是正常渲染的一种特殊情况),我们就走到了else语句下,关键代码createViewFromTag()生成了View。

那我们继续跟踪,看一下createViewFromTag执行了什么操作:

View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
            boolean ignoreThemeAttr) {
        if (name.equals("view")) {
            name = attrs.getAttributeValue(null, "class");
        }
       ...省略
        try {
            View view;
            if (mFactory2 != null) {
                view = mFactory2.onCreateView(parent, name, context, attrs);
            } else if (mFactory != null) {
                view = mFactory.onCreateView(name, context, attrs);
            } else {
                view = null;
            }

            if (view == null && mPrivateFactory != null) {
                view = mPrivateFactory.onCreateView(parent, name, context, attrs);
            }

            if (view == null) {
                final Object lastContext = mConstructorArgs[0];
                mConstructorArgs[0] = context;
                try {
                    if (-1 == name.indexOf('.')) {
                        view = onCreateView(parent, name, attrs);
                    } else {
                        view = createView(name, null, attrs);
                    }
                } finally {
                    mConstructorArgs[0] = lastContext;
                }
            }
            return view;
        } catch (InflateException e) {
            throw e;
        } catch (ClassNotFoundException e) {
            ...省略
        } catch (Exception e) {
            ...省略
        }
    }

我们还是讲部分代码省略了,从try代码块开始看,当mFactory2或者mFactory不为null时,View是由它们的onCreateView方法生成的,否则使用系统默认创建View的流程。系统默认创建View的流程是通过判断标签名称有没有包含".",如果没有则将前缀"android.view."添加到标签名前面,最终调用LayoutInflater的createView()方法,然后返回View。
到这里我们就知道了LayoutInflater根据布局文件来渲染View的主要流程:先通过布局文件的资源ID创建XmlResourceParser解析器对象,然后利用该对象递归解析布局文件,根据解析出来的标签名生成View,最终返回层级视图View。而如果LayoutInflater设置了Factory2或者Factory,那么在创建View时都会调用Factory2或者Factory的onCreateView方法,所以我们可以在View创建之前在onCreateView中做一些相关逻辑,比如说换肤。

LayoutInflater之Factory接口

未完待续...

相关文章

  • Android换肤机制

    LayoutInflater 我们经常使用LayoutInflater将布局文件渲染成View层级视图,那么具体是...

  • Android换肤机制

    参考资料: Android换肤技术总结 Android应用程序插件化研究之AssetManager Android...

  • 夜间模式实践

    现状 夜间模式是android换肤的一种,关于换肤的相关知识总结,大家可以参考这篇文章Android换肤技术总结-...

  • Android插件化系列第(四)篇---插件加载机制两种方案

    这篇博客说说插件的加载机制,建议阅读Android插件化系列第(二)篇---动态加载技术之apk换肤了解类的加载机...

  • Android动态换肤框架-实现换肤

    1、换肤流程 2、采集流程 3、Android资源查找流程 4、采集需要换肤的控件 换肤我们需要换所有可能需要换的...

  • android 夜间模式(换肤)总结

    一、android 平台常见的换肤方案. Android 平台常见的额换肤方式总结起来有如下三种: 1.设置set...

  • Android换肤方案总结

    这篇总结也是拖了很久了,欠下的技术债必须得偿还啦~ Android换肤在使用场景上可以区分为静态换肤/动态换肤、应...

  • Android换肤方案

    没有任何侵入型的一行代码实现动态换肤的android换肤组件 欢迎star https://github.com/...

  • 原来Android换肤如此简单

    这是一个Android换肤的库,代码量极少,支持换肤的情况还比较多,提供了以下功能: 无需重启,一键换肤效率高 支...

  • Android-skin-loader 换肤总结

    前言 最近有个换肤的需求。基于github上的这个开源框架Android-Skin-Loader。这个框架的换肤机...

网友评论

      本文标题:Android换肤机制

      本文链接:https://www.haomeiwen.com/subject/cwfpsxtx.html