Android插件化架构研究遇阻:自定义类加载引发RecyclerView类型转换异常
解决插件化架构中RecyclerView的ClassCastException问题
嘿,这个问题我之前做Android插件化架构的时候也踩过一模一样的坑!明明看着是同一个RecyclerView类,却死活转不了,那种挫败感太懂了。
先再明确下核心原因:JVM判断两个类是否为同一个,不仅要看全类名,还要看加载它们的类加载器是否相同。你这里的情况就是:宿主里的RecyclerView是系统/宿主类加载器加载的,而插件里的RecyclerView被另一个自定义类加载器加载了,JVM直接把它们当成完全不同的类,自然就抛出ClassCastException了。
下面给你几个实操性的解决方案:
1. 统一核心类的加载逻辑
把Android支持库(或AndroidX)里的核心类(比如RecyclerView、AppCompat这些)统一交给宿主的类加载器来加载,自定义类加载器只负责加载插件独有的业务类。
你可以在自定义类加载器的loadClass方法里做拦截判断:
@Override protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 核心类(系统类、支持库/AndroidX类)交给父类加载器(宿主类加载器)处理 if (name.startsWith("android.") || name.startsWith("android.support.v7.widget.") || name.startsWith("androidx.recyclerview.widget.")) { return getParent().loadClass(name); } // 插件自身的业务类才走自定义加载逻辑 synchronized (getClassLoadingLock(name)) { Class<?> loadedClass = findLoadedClass(name); if (loadedClass == null) { loadedClass = findClass(name); // 从插件APK里加载类 } if (resolve) { resolveClass(loadedClass); } return loadedClass; } }
2. 确保视图初始化的类加载器上下文正确
如果插件里有在后台线程初始化视图的逻辑,一定要把线程的上下文类加载器设置为你的自定义类加载器,避免视图类被其他类加载器意外加载:
Thread currentThread = Thread.currentThread(); ClassLoader originalClassLoader = currentThread.getContextClassLoader(); try { // 切换到插件类加载器上下文 currentThread.setContextClassLoader(yourCustomClassLoader); // 这里执行视图初始化、 findViewById 等操作 } finally { // 恢复原来的类加载器 currentThread.setContextClassLoader(originalClassLoader); }
3. 调整插件打包配置,避免重复打包核心类
插件打包时,一定要把支持库/AndroidX的类排除掉,不然插件APK里会自带一份RecyclerView类,加载时就会和宿主的类冲突。在插件模块的build.gradle里添加打包配置:
android { packagingOptions { // 排除AndroidX RecyclerView相关类 exclude 'androidx/recyclerview/widget/**' // 如果用的是旧的support库,就排除对应的路径 // exclude 'android/support/v7/widget/**' } }
另外提醒下,如果已经迁移到AndroidX,记得把所有相关的包名替换成androidx.*,别和旧的support库混着用,这也容易引发类加载冲突。
内容的提问来源于stack exchange,提问作者agicquel
相关产品推荐
相关产品推荐

