Fragment依赖冲突引起的一个bug及解决
这几天碰到一个显示bug,Activity A页面中的一个部分本来是没有数据不应该显示出来的,但是却显示出来了。
查看代码,发现这个部分是属于fragment B的。如果没有数据,B的根布局会被setVisibilty(gone)
,但是最终显示效果却是B被显示出来了,这就很诡异了。于是我对B的根布局(一个自定义view)的setVisibilty
方法打上断点,发现B被fragmentmanager 调用了getView().setVisibilty(Visible)
,而B的getView()
就是其根布局,终于真相大白了。
那问题来了,相关代码已经一两年没有动 了,为什么现在出问题了?通过debug,发现debug走的fragment版本是25.1.0,但项目引入的fragment的版本明明是24.2.0。怀疑是和fragment的版本有关,于是调用gradlew:app:dependencies
命令,查看项目的依赖,发现最近有个新引入的库,其依赖了support-v4,而且版本是25.1.0。于是尝试exclude support库
compile("依赖") {
exclude group: "com.android.support"
}
再次打包运行,发现问题解决了。看来确实是25.1.0版本的fragment 出了问题。对比下代码,发现确实24.2.0版本和25.1.0版本的framgnet内部实现有了不少变化,v25.1.0多了一个FragmentTransition类,在此类中多次调用fragment.getView().setVisibility()
。
所以:
- 控制fragment的显示/隐藏,最好还是通过fragmentmanager去操作,不要通过控制fragment的根布局的vibibilty去操作。
- 接入新的依赖时注意其引入的间接依赖,避免依赖冲突产生的依赖版本提升
将support库升级到25.3.1版本后又发现fragmentmanager
内部没有再调用fragment.getView().setVisibility()
了,所以直接设置fragment根布局的Visibilty也就没有问题了。
但我觉得,最好还是不要这么做,毕竟support库的framgnet实现经常变,说不定哪天又出问题了。而且fragment毕竟不是view,要控制显示/隐藏,还是通过framgent的方式去做,不能像View那样直接setVisibilty.
另外,接入第三方lib是不可避免的事,怎么能避免依赖版本冲突带来的影响呢?这里有两种解决版本:
- 添加依赖时exclude已有的依赖,如上文的
exclude group: "com.android.support"
这样 - 在集成打包的module中,指定某个依赖的版本如:
compile("com.android.support:support-v4:24.2.0") {
force = true
}
这样的话,即使其他间接依赖引入了版本高于24.2.0的v4包(如25.1.0),在打包时最终集成进去的也会是24.2.0版本的v4包