android 解决2.3.5bottomnavigation的fragment重建的问题
在开发软件的时候,用到了bottomnavigation+fragment的框架,用过的人都知道,当点击下方的bottom的时候,会刷新当前fragment页面,且会重建当前fragment,如下所示
可以看见 当我点击bottom的icon的时候,当前fragment进行了重建,并且重新进行了网络请求。这在正常情况下是不合理的。
查看导航NavHostFragment可以看到,创建了一个FragmentNavigator
protected Navigator extends FragmentNavigator.Destination> createFragmentNavigator() {
return ne FragmentNavigator(requireContext(), getChildFragmentManager(),
getContainerId());
}
在这个FragmentNavigator中的navigator方法中可以看到,当前框架是通过
ft.replace(mContainerId, frag);
replace方法来替换的。显然是这里的问题。
这种问题,谷歌替我们也想到了。在最新的2.4.0版本中得到了修改,支持了回退栈,不过2.4.0是alpha版本,并没有正式发布
Android Developers Navigation
但其实替换成2.4.0好像也没有完全符合我的需求。其实际效果如下
1.当我点击当前页面的时候,fragment没有进行重建
2.当我点击其他页面然后切换回来的时候,fragment进行了重建,并且重新执行网络请求
3.当此页面存在下啦加载等功能的时候,如不做特殊处理,来回切换页面,会使数据混乱
查看源码可以看到
增加了一个集合用于存放fragment实例,切换的时候保存了当前fragment的一些状态,在重建的时候恢复,实际上仍然使用replace方法切换fragment
ft.replace(containerId, frag)
如此功能,并不能简单方便的实现我们正常使用的切换功能。且2.4.0仍然alpha版本,所以在2.3.5中进行部分修改
在开发中使用navgation,需要在主activity中的fragment标签中添加 NavHostFragment
就是在这个fragment中构建了导航器navigator,我们可以自定义fragment继承NavHostFragment,然后在其中创建自定义的navigator,将核心的replace代码修改成sho/hide方法
class FixNavHostFragment : NavHostFragment() {
override fun createFragmentNavigator(): Navigator {
return FixNavigator(requireContext(), childFragmentManager, containerId)
}
private val containerId: Int
get() {
val id = id
return if (id != 0 && id != Vie.NO_ID) {
id
} else R.id.nav_host_fragment_container
}
}
这个代码很简单看function名字就可以知道其作用,用来create一个navigator,创建一个自定义navigator继承于FragmentNavigator
@Navigator.Name("fragment")
class FixNavigator(
private val mContext: Context,
private val mFragmentManager: FragmentManager,
private val mContainerId: Int
) : FragmentNavigator(mContext, mFragmentManager, mContainerId) {
}
不要忘记添加注解Navigator.Name 用来标记这个navigation导航器
主要重写其中的navigator方法即可
其中大多数代码还是CV过来就可以了,主要修改replace方法,如下
@Navigator.Name("fragment")
class FixNavigator(
private val mContext: Context,
private val mFragmentManager: FragmentManager,
private val mContainerId: Int
) : FragmentNavigator(mContext, mFragmentManager, mContainerId) {
...省略代码
//获取当前需要显示的fragment
val fragment = mFragmentManager.primaryNavigationFragment
if (fragment != null) {
ft.setMaxLifecycle(fragment, Lifecycle.State.STARTED)
ft.hide(fragment)
}
var frag: Fragment? = null
//获取id
val tag = destination.id.toString()
frag = mFragmentManager.findFragmentByTag(tag)
if (frag != null) {
ft.setMaxLifecycle(frag, Lifecycle.State.RESUMED)
ft.sho(frag)
} else {
frag = instantiateFragment(mContext, mFragmentManager, className, args)
frag.arguments = args
ft.add(mContainerId, frag, tag)
}
//ft.replace(mContainerId, frag);
ft.setPrimaryNavigationFragment(frag)
@IdRes val destId = destination.id
//父类中的mbackStack为private的,需要通过反射获取
var mBackStack: ArrayDeque? = null
try {
val field = FragmentNavigator::class.java.getDeclaredField("mBackStack")
field.isAessible = true
mBackStack = field[this] as ArrayDeque
} catch (e: NoSuchFieldException) {
e.printStackTrace()
} catch (e: IllegalAessException) {
e.printStackTrace()
}
val initialNavigation = mBackStack!!.isEmpty()
...省略代码
}
修改完成之后记得在xml中设置成自定义的fragment,且在activity中做如下修改
val nav: BottomNavigationVie = binding.navVie
val navController = findNavController(R.id.nav_host_fragment_activity_main)
nav.setOnItemSelectedListener {
navController.navigate(it.itemId)
true
}
// nav.setupWithNavController(navController)
完成,运行。
空调维修
- 我的世界电脑版运行身份怎么弄出来(我的世界
- 空调抽湿是什么意思,设置抽湿的温度有什么意
- 方太燃气灶有一个打不着火 怎么修复与排查方法
- 夏季免费清洗汽车空调的宣传口号
- 清洗完空调后出现漏水现象
- iphone6能玩什么游戏(iphone6游戏)
- 如何设置电脑密码锁屏(如何设置电脑密码锁屏
- win10删除开机密码提示不符合密码策略要求
- 电脑w7显示不是正版(w7不是正版怎么解决)
- 万家乐z8热水器显示e7解决 怎么修复与排查方法
- 1匹空调多少瓦数(1匹空调多少瓦)
- 安卓手机连接电脑用什么软件好(关于安卓手机
- 电脑网页看视频卡是什么原因(爱拍看视频卡)
- 华帝燃气灶点火器一直响然后熄火怎么办:问题
- 电脑壁纸怎么换(关于电脑壁纸怎么换的介绍)
- 冬天空调的出风口应该朝什么方向(冬天空调风