插件框架一之解决插件布局自定义组件无法使用问题

问题:
在插件中的xml布局中的自定义组件无法使用。

分析:
1、LayoutInflater.from(Context)创建LayoutInflater时,执行了Context的getSystemService方法。
LayoutInflater:
这里写图片描述
2、Context的getSystemService方法在Activity, ContextThemeWrapper中实现,在ContextThemeWrapper对LAYOUT_INFLATER_SERVICE服务进行处理,并通过mBaseContext来获取LayoutInflater
ContextThemeWrapper:
这里写图片描述
3、mBaseContext是在android.app.ContextImpl中处理LayoutInflater服务,所以每个activity/ContextWrapper只有一个LayoutIflater
ContextImpl:
private static final HashMap SYSTEM_SERVICE_MAP = new HashMap();
这里写图片描述
4、在插件中传的是Context是主工程的Context,LayoutInflater在ContextThemeWrapper中主工程的Context。LayoutInflater在解析布局文件中的自定义组件时,通过context.getClassLoader()来加载实例化,而context.getClassLoader()所得到的ClassLoader正是主工程的ClassLoader,其中不包含插件类。
LayoutInflater:
这里写图片描述
5、所以重点是要替换LayoutInflater解析自定义组件时所用到的ClassLoader,但是通过主工程context所得到的LayoutInflater最终都是会调用主工程的ClassLoader,而到导致无法实例化自定义组件。

解决方案:
通过创建新的Context并重写getClassLoader函数,返回插件ClassLoader。
1、Activity在父类ContextWrapper中通过mBaseContext获取ClassLoader,其中通过反射等方式替换主context的ClassLoader方式比较繁琐而且降低了安全性,所以可以选择创建一个新的插件Context。具体做法的是新建继承Context的JarContext类—>传入主Context和插件ClassLoader—>重写getClassLoader方法,并返回插件ClassLoader—>重新getSystemService方法,绑定一个LayoutInflater,保证一个JarContext只有一个LayoutInflater—>重写其他方法通过主工程context执行。
JarContext:
这里写图片描述
这里写图片描述
2、由于插件类是通过ClassLoader反射获取得到到的,所以插件ClassLoader的获取可以通过Class.getClassLoader获取得到。
3、LayoutInflater的构造函数处于protecte状态,所以一般都是通过context..getSystemService(Context.LAYOUT_INFLATER_SERVICE)得到,但是通过分析如此方法无法替换ClassLoader,所以我们需要创建一个新的LayoutInflater,创建LayoutInflater的时候传入JarContext,得到一个LayoutInflater实例。
4、最后通过跟JarContext绑定的LayoutInflater实例即可解析包含自定义组件的插件布局了。
这里写图片描述

弊端:
由于LayoutInflater的Context是新的JarContext,并且其ClassLoader是插件DexClassLoader,所以在解析布局的时候会将简写标签(如EditText)添加android.view前缀,但是EditText是andorid.widget包下的,所以ClassLoader加载时会报ClassNotFoundException异常。
这里写图片描述
这里写图片描述
这里写图片描述
解决办法:在layout布局中,给所有标签补全前缀,从而LayoutInflater解析的时候不会添加android.view前缀。
这里写图片描述

备注:每个Context对应唯一一个LayoutInFlater。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值