王学岗csdn(10)————动态式换肤框架分析,与手写实现(一)

换肤分为两种,内置换肤和动态换肤
内置换肤:
在APK包中存在多种资源(图片、颜色值),用于换肤时候切换,缺点是自由度低,文件大。
比如我们app常见的日间模式和夜间模式。
动态换夫:
运行时动态加载皮肤包(皮肤包就是一个apk),下载apk到sd卡或者其它存储路径,然后加载进来。
在这里插入图片描述
是如何采集皮肤的呢?就是上图中我们的采集流程
我们打开setContentView 的源码。跟踪下去,发现如下代码:

 @Override
    public void setContentView(int resId) {
        ensureSubDecor();
        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
        contentParent.removeAllViews();
        LayoutInflater.from(mContext).inflate(resId, contentParent);
        mAppCompatWindowCallback.getWrapped().onContentChanged();
    }

可以发现xml文件是通过布局加载器加载进来的。
继续跟踪inflate()的源码,

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
        final Resources res = getContext().getResources();
        if (DEBUG) {
            Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                  + Integer.toHexString(resource) + ")");
        }

        View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
        if (view != null) {
            return view;
        }
        XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }

我们可以看到,在这段代码中,它获得了XML解析器。XML解析器会一个节点一个节点的去解析。一旦解析到某个节点,就会创建相应的View,我们看下写源码

void rInflate(XmlPullParser parser, View parent, Context context,
            AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
              final String name = parser.getName();
              final View view = createViewFromTag(parent, name, context, attrs);
            }

我们看下createViewFromTag源码

 View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
            boolean ignoreThemeAttr) {
            //系统的自带的View用工厂模式创建
            View view = tryCreateView(parent, name, context, attrs);
            //包含"."的则表示这个View是自定义View
              if (-1 == name.indexOf('.')) {
                        view = onCreateView(context, parent, name, attrs);
                    } else {
                        view = createView(context, name, null, attrs);
                    }
            }

继续追踪View view = tryCreateView(parent, name, context, attrs);源码

 public final View tryCreateView(@Nullable View parent, @NonNull String name,
        @NonNull Context context,
        @NonNull AttributeSet attrs) {
        if (name.equals(TAG_1995)) {
            // Let's party like it's 1995!
            return new BlinkLayout(context, attrs);
        }

        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);
        }

        return view;
    }

使用工厂方法创建了我们的View

上面我跟大家分析了setContentView()方法的源码。可能看官会有疑问,这跟我们本篇文章有什么关系呢?
如果我们想达到一个换肤的效果,那么我们需要在OnCreate()方法加载布局的时候就把换肤加载好,我们需要替换的View要配置好。
开始敲代码啦
我们创建一个Android library ——skin_core。并把它添加到我们app的依赖
用到的技术

  //我们用布局加载器的时候,传入的Context应该是MainActivity,而不是MyApplication。
        //所以这里我们需要把Activity添加到生命周期的回调注册方法中
        /**
         *提供了一个应用生命周期回调的注册方法,用来对应用的生命周期进行集中管理。
         * 这个接口叫registerActivityLifecyleCallbacks,可以通过它注册自己的ActivityLifeCycleCallback,
         * 每一个activity的生命周期都会回调到这里的对应方法
         */
        application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
                
            }

            @Override
            public void onActivityStarted(@NonNull Activity activity) {

            }

            @Override
            public void onActivityResumed(@NonNull Activity activity) {

            }

            @Override
            public void onActivityPaused(@NonNull Activity activity) {

            }

            @Override
            public void onActivityStopped(@NonNull Activity activity) {

            }

            @Override
            public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {

            }

            @Override
            public void onActivityDestroyed(@NonNull Activity activity) {

            }
        });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值