关于viewpager常见的泄漏
在一个页面中 如果有用到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 Fragmentval fragmentWorkout = SportFragment.newInstance()val fragmentChallenges = EntertainmentFragment.newInstance()fragments.add(fragmentHome)fragments.add(fragmentWorkout)fragments.add(fragmentChallenges)BarUtils.setStatusBarLightMode(requireActivity().window, true)fromFragment = fragmentHomeval transaction: FragmentTransaction = requireActivity().supportFragmentManager.beginTransaction()if (hopeToPosition == 1) {fromFragment = fragmentWorkout(fromFragment as SportFragment).changeTab(workoutType)dataBinding.navigationLaunch.menu.getItem(1).isChecked = truetabIndex = 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().supportFragmentManagerval 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().supportFragmentManagerval transaction = manger.beginTransaction()val tag = "fragment_$position"LogUtils.d("linlian mainfragment switchFragment $position")// 查找已存在的 Fragmentval existingFragment = manger.findFragmentByTag(tag)val newFragment = when (position) {0 -> ARouter.getInstance().build(RrouterConstant.HOME_MAIN_FRAGMENT).navigation() as Fragment1 -> SportFragment.newInstance()else -> EntertainmentFragment.newInstance()}if (existingFragment != null) {transaction.show(existingFragment)} else {transaction.add(R.id.vp_fragment, newFragment, tag)}fragmentTags[position] = tag// 隐藏其他 Fragmentmanger.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