传递参数类型错误:模块间Serializable接口跨组件传参异常排查
问题排查与解决方案
嘿,这个问题我之前做Android模块化项目时也踩过!本质是跨模块类加载和序列化的坑,我给你拆解下原因和靠谱的解决办法:
核心原因拆解
你碰到的「Wrong type of parameter passed」错误,主要是这几个原因导致的:
- 类加载器打架了:Android的不同模块(base、market、app)默认有各自的类加载器,如果
BaseNavigationInterface在不同模块里被加载成了“不一样的类”(比如依赖配置错了,导致类路径不一致),系统就会认为你传的类型不对。 - Serializable的回调传递有坑:你在app模块里传的应该是
BaseNavigationInterface的匿名实现类吧?这个实现类的代码只在app模块里有,market模块的类加载器在反序列化Intent里的对象时,根本找不到这个类的定义,自然就报类型错误了。 - 依赖配置不对:如果market模块对base模块的依赖不是
implementation(比如用了compileOnly这种只编译不打包的依赖),运行时market模块找不到BaseNavigationInterface的类,也会触发类型校验失败。
可行解决方案
针对不同场景,给你几个实用的解决办法:
方案1:换个姿势实现回调(最推荐)
用Serializable传递接口回调本身就不太稳妥,更靠谱的是用SharedFlow或者EventBus来做跨模块通信:
- 举个SharedFlow的例子,先在base模块定义一个事件容器:
// base模块里的全局事件总线 object NavigationEventBus { private val _navEvents = MutableSharedFlow<Int>() val navEvents = _navEvents.asSharedFlow() suspend fun triggerItemClick(itemId: Int) { _navEvents.emit(itemId) } } - 然后在app模块里订阅事件,处理原来的回调逻辑:
lifecycleScope.launch { NavigationEventBus.navEvents.collect { itemId -> // 这里写原来onItemClicked里的代码 } } - 最后在market模块里需要触发回调的地方发送事件:
这种方式完全避开了序列化的坑,还能灵活处理跨模块通信。lifecycleScope.launch { NavigationEventBus.triggerItemClick(点击的itemId) }
方案2:修复Serializable的类可见性问题
如果你一定要用Intent传递接口,得确保实现类能被market模块找到:
- 把
BaseNavigationInterface的实现类移到base模块里(或者让market模块依赖包含这个实现类的模块),这样market的类加载器能找到它。 - 检查所有模块对base模块的依赖,必须用
implementation,保证全模块加载的是同一个BaseNavigationInterface类:
在market和app模块的build.gradle里都要这么写:dependencies { implementation project(':base') }
方案3:用Parcelable包装事件(应急用)
因为接口不能直接实现Parcelable,你可以用一个Parcelable的事件类来传递信息,然后通过Activity的返回结果来处理:
- 在base模块定义一个Parcelable类:
@Parcelize data class NavItemClickEvent(val itemId: Int) : Parcelable - market模块里不用传接口,而是在需要回调时把这个事件通过
setResult返回给app模块,app模块用ActivityResultContracts接收并处理。
总结
优先选方案1,用Flow或者EventBus来做跨模块回调,彻底避开序列化的坑。如果一定要用Intent传递,先把依赖配置和类可见性的问题解决掉。
内容的提问来源于stack exchange,提问作者just
相关产品推荐
相关产品推荐

