Android Fragment在特殊情况下的生命周期

一、前言

对于Fragment的使用和生命周期网上有很多说明(传送门),此篇文章只是记录一些特殊情况下的Fragment的生命周期执行情况。

二、发现问题

在开发中,经常使用底部导航功能,一般采用RadioGroup+Fragment实现界面切换,例如

class MainActivity : AppCompatActivity(){
	private var mFragments: Array<Fragment?> = arrayOf((HomeFragment()), null, null, null)
	...

    /**
     * Fragment切换
     */
    private fun selectedFragment(itemId: Int) {
        val fragmentTransaction = supportFragmentManager.beginTransaction()
        Log.i("itemId", "" + itemId)
        val fragment = mFragments[itemId]
        //先检查Fragment是否创建
        if (fragment == null) {
            when (itemId) {
                0-> mFragments[0] = HomeFragment()
                1-> mFragments[1] = DeviceFragment()
                2-> mFragments[2] = TaskFragment()
                3-> mFragments[3] = MangerFragment()
            }
            //添加到管理类
            fragmentTransaction.add(R.id.linearLayout, mFragments[itemId]!!)
        }
        
        for (i in mFragments.indices) {
            val fragment = mFragments[i]
            fragment?.let {
                if (i != itemId) {
                    fragmentTransaction.hide(fragment)
                } else {
                    fragmentTransaction.show(fragment)
                }
            }
        }
        fragmentTransaction.commit()
    }
    
	...

}

但是我发现使用show/hide 切换Fragment时,onResumeonPause并没有执行。fragment第一次创建的时候执行了onResume方法,但是后续的切换中只是调用show/hide,并不走onResumeonPause。如果我们需要处理Fragment的可见和不可见时该怎么办呢?

三、解决问题

3.1 未使用Viewpager

其实在调用show/hide方法会执行onHiddenChanged方法,true为当前界面hide

    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
    }

但是如果是在fragment启动新页面和返回来并没有执行onHiddenChanged方法,而是所有fragment都执行了onPauseonResume,所以我们需要结合起来进行判断

class HomeFragment: Fragment(){
    //是否运行onHiddenChanged方法
    private var isHiddenChanged = false
    //是否可见
    private var isUserVisible = false

    override fun onResume() {
        super.onResume()
        //如果没有执行onHiddenChanged方法,则是第一个fragment
        if (!isHiddenChanged) {
            isHiddenChanged = true
            //记录页面可见状态
            isUserVisible = true
            onUserVisible()
        } else {
            //如果当前页面可见的
            if (isUserVisible) {
                onUserVisible()
            }
        }
    }

    override fun onPause() {
        super.onPause()
        //如果当前页面可见的
        if (isUserVisible) {
            onUserInvisible()
        }
    }
    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
        //如果是隐藏
        if (hidden) {
            //如果当前fragment已经页面可见了,那么就要执行不可见方法
            if (isUserVisible) {
                isUserVisible = false
                onUserInvisible()
            }
        } else {
            //如果是显示
            onUserVisible()
            //记录页面可见状态
            isUserVisible = true
        }
        isHiddenChanged = true
    }
    
    /**
     * 当前Fragment不可见执行方法
     */
    private fun onUserInvisible() {}

    /**
     * 当前Fragment可见执行方法
     */
    private fun onUserVisible() {}
}

3.2 使用Viewpager

如果切换时使用的是viewpager,例如

class MainActivity : AppCompatActivity(){
	private var mFragments: Array<Fragment?> = arrayOf((HomeFragment()), DeviceFragment(), TaskFragment(), MangerFragment())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mViewPager.setAdapter(MyFragmentPagerAdapter(getSupportFragmentManager(), mFragments));
	}
	...

    /**
     * Fragment切换
     */
    private fun selectedFragment(itemId: Int) {
		mViewPager.setCurrentItem(itemId)
    }
    
	...
}
class MyFragmentPagerAdapter(fm: FragmentManager, private val array: Array<Fragment>) : FragmentStatePagerAdapter(fm) {
    override fun getItem(position: Int): Fragment {
        return array[position]
    }
    
    override fun getCount(): Int {
        return array.size
    }
}

经过实验发现根本就不走onHiddenChanged方法,fragment在viewpager中会执行setUserVisibleHint(boolean isVisibleToUser)方法

    private var isFirstResume = true
    private var isFirstVisible = true
    private var isUserVisible = false
    private var isPrepared: Boolean = false

    override fun onResume() {
        super.onResume()

        if (isFirstResume) {
            isFirstResume = false
            return
        }

        if (userVisibleHint) {
            isUserVisible = true
            onUserVisible()
        }

    }

    override fun onPause() {
        super.onPause()

        if (isFirstResume) {
            isFirstResume = false
            return
        }
        if (userVisibleHint) {
            if(isUserVisible){
                isUserVisible = false
                onUserInvisible()
            }
        }

    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        initPrepare()
    }

    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)

        if (isVisibleToUser) {
            if (isFirstVisible) {
                isFirstVisible = false
                initPrepare()
            } else {
                isUserVisible = true
                onUserVisible()
            }
        } else {
            if(isUserVisible){
                isUserVisible = false
                onUserInvisible()
            }
        }
    }

    private fun initPrepare() {
        if (isPrepared) {
            isUserVisible = true
            onUserVisible()
        } else {
            isPrepared = true
        }
    }

    open fun onUserVisible() {
        Log.e(ViewPagerFragment.TAG, "$mTag ===  onUserVisible")
    }

    open fun onUserInvisible() {
        Log.e(ViewPagerFragment.TAG, "$mTag ===  onUserInvisible")
    }

    override fun onDestroyView() {
        super.onDestroyView()

        isFirstResume = true
        isFirstVisible = true

        isUserVisible = false
        isPrepared = false
    }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值