Android 插件版本切换崩溃(Resource not found)

综述:

主工程加载插件工程(把插件做成皮肤、特殊的View等)。当插件工程更新代码、布局时,Resource ID因新增的id导致编译后id数值发生改变。而当主程序加载 更新前的主题(A主题),再加载更新后的(B主题),就会导致View inflate为null。

有个前提条件是 升级后,自定义View的全限定包名(如com.test.TestLayout)不变。LayoutInflater inflate view时,如果发现是已经加载过的View,就直接用之前的ClassLoader来加载(之后的Log可以看出来)。

解决方法就是在LayoutInflater采用默认方式加载缓存View的时,抢先用我们自己的ClassLoader进行加载。通过LayoutInflater setFactory实现,详细资料点击打开链接

之前Host代码:

主工程加载插件:

 String layoutName = getStyleLayout();
        if (!TextUtils.isEmpty(layoutName)) {
            Resources resources = mContext.getResources();
            String packageName = mContext.getPackageName();
            int layoutId = resources.getIdentifier(layoutName, "layout", packageName);
            if (layoutId > 0) {
                try {

                    if (mLayoutInflater == null) {
                        mLayoutInflater = LayoutInflater.from(mContext);
                    }
                    mLayoutInflater = mLayoutInflater.cloneInContext(mContext);
                    Log.e("test", "host 5: " + mLayoutInflater.getContext().getClassLoader().toString());
                    return (mStyleView = mLayoutInflater.inflate(layoutId, parent, false));

插件自定义View(com.mytest.view.TestView):

        mDateWidget = (IBaseWidget) findViewById(R.id.widget_date);

        Log.e("test", "plug 1: " + getClass().getClassLoader().toString());
        mDateWidget.setClickable(false);

打Log可以看到,新主题切换旧主题,用的仍旧是旧主题的ClassLoader


解决方案:

主工程加载View代码:

    public View createStyleView(ViewGroup parent) {
        if (parent == null || mContext == null) {
            return null;
        }

        String layoutName = getStyleLayout();
        if (!TextUtils.isEmpty(layoutName)) {
            Resources resources = mContext.getResources();
            String packageName = mContext.getPackageName();
            int layoutId = resources.getIdentifier(layoutName, "layout", packageName);
            if (layoutId > 0) {
                try {
                    updateLayoutInflater();
                    return (mStyleView = mLayoutInflater.inflate(layoutId, parent, false));
                } catch (InflateException e) {
                    e.printStackTrace();
                }
            }
        }

        return null;
    }
		
		
    private void updateLayoutInflater() {
        if (mLayoutInflater == null) {
            mLayoutInflater = LayoutInflater.from(mContext);
        }
        mLayoutInflater = mLayoutInflater.cloneInContext(mContext);
        mLayoutInflater.setFactory(new LayoutInflater.Factory() {
            @Override
            public View onCreateView(String name, Context context, AttributeSet attrs) {
                View customView = null;
                if (mLayoutInflater != null && !TextUtils.isEmpty(name) && name.startsWith("com.mytest.view")) {
                    Context plugContext = mLayoutInflater.getContext();
                    if (null != plugContext) {
                        try {
                            Class<?> customViewClass = plugContext.getClassLoader().loadClass(name);
                            Object customViewObject = customViewClass.getDeclaredConstructor(Context.class, AttributeSet.class).newInstance(plugContext, attrs);
                            if (customViewObject instanceof  View) {
                                customView = (View) customViewObject;
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                return customView;
            }
        });
    }










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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值