在一个页面中 如果有用到tab,有需要进行fragment的切换,经常就看到了
private var fragments = arrayListOf<Fragment>()
private fun initFragment() {
arguments?.let {
hopeToPosition = it.getInt(IntentConstant.MAIN_PAGE_GO, 0)
workoutType = it.getInt(IntentConstant.WORKOUT_PAGE_GO, 0)
challengesTabId = it.getLong(IntentConstant.CHALLENGES_TAB_ID, 0L)
}
val fragmentHome = ARouter.getInstance().build(RrouterConstant.HOME_MAIN_FRAGMENT).navigation() as Fragment
val fragmentWorkout = SportFragment.newInstance()
val fragmentChallenges = EntertainmentFragment.newInstance()
fragments.add(fragmentHome)
fragments.add(fragmentWorkout)
fragments.add(fragmentChallenges)
BarUtils.setStatusBarLightMode(requireActivity().window, true)
fromFragment = fragmentHome
val transaction: FragmentTransaction = requireActivity().supportFragmentManager.beginTransaction()
if (hopeToPosition == 1) {
fromFragment = fragmentWorkout
(fromFragment as SportFragment).changeTab(workoutType)
dataBinding.navigationLaunch.menu.getItem(1).isChecked = true
tabIndex = hopeToPosition
}
transaction.replace(R.id.vp_fragment, fromFragment!!)
transaction.commit()
}
private fun switchFragment(from: Fragment?, to: Fragment?, isResume: Boolean = false) {
if (from !== to) {
val manger: FragmentManager = requireActivity().supportFragmentManager
val transaction = manger.beginTransaction()
if (!to!!.isAdded) {
if (from != null) {
transaction.hide(from)
}
if (to != null) {
if (isResume) {
transaction.add(R.id.vp_fragment, to).commitAllowingStateLoss()
} else {
transaction.add(R.id.vp_fragment, to).commit()
}
}
} else {
if (from != null) {
transaction.hide(from)
}
if (to != null) {
if (isResume) {
transaction.show(to).commitAllowingStateLoss()
} else {
transaction.show(to).commit()
}
}
}
}
fromFragment = to
}
但是这样比如在 mainfragment就就强引用了子fragment,这种强应用leakcanary不会报异常,但是Android studio的profile会报泄漏
修复方案
private val fragmentTags = mutableMapOf<Int, String>()
private fun switchFragment(position: Int) {
val manger: FragmentManager = requireActivity().supportFragmentManager
val transaction = manger.beginTransaction()
val tag = "fragment_$position"
LogUtils.d("linlian mainfragment switchFragment $position")
// 查找已存在的 Fragment
val existingFragment = manger.findFragmentByTag(tag)
val newFragment = when (position) {
0 -> ARouter.getInstance().build(RrouterConstant.HOME_MAIN_FRAGMENT)
.navigation() as Fragment
1 -> SportFragment.newInstance()
else -> EntertainmentFragment.newInstance()
}
if (existingFragment != null) {
transaction.show(existingFragment)
} else {
transaction.add(R.id.vp_fragment, newFragment, tag)
}
fragmentTags[position] = tag
// 隐藏其他 Fragment
manger.fragments.forEach { frag ->
LogUtils.d("linlian MainFragment hide $frag,tag =${frag.tag},valuse=${fragmentTags.values}")
if (frag.tag != null && frag.tag != tag && fragmentTags.values.contains(frag.tag)) {
LogUtils.w("linlian MainFragment hide frag !!!$frag")
transaction.hide(frag)
}
}
transaction.commit()
}
这样就可以不直接引用fragment