ViewPager + Fragment注意事项

前言:使用ViewPager和fragment情况很常见,然而今天却遇到了问题,通过查阅ViewPager相关资料发现是ViewPager缓存机制造成的,在此记录一下,避免再次入坑。

问题:在一个包含ViewPager页面里包含两个fragment(OneFragment、TwoFragment),在activity的onResume()中调用加载数据方法,然而当前页面切至后台并发生被系统回收后,再次切回该页面时只需onResume发现没有加载数据。主要代码如下:

1、页面代码:

class TestActivity : BaseActivity() {
    private val mFragmetList = mutableListOf<BaseFragment>()
    private var mCurrentFragment: BaseFragment? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_me_order)
        initView()
    }

    private fun initView() {
	    mCurrentFragment = OneFragment()
	    mFragmetList.add(mCurrentFragment)
	    mFragmetList.add(TwoFragment())
        
        viewPager.adapter = ViewPagerAdapter(supportFragmentManager, mFragmetList)
        viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            override fun onPageScrollStateChanged(p0: Int) {}

            override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {}

            override fun onPageSelected(p0: Int) {
                setVisiable(false)//设置当前fragment不可见
                mCurrentFragment = mFragmetList[p0] as BaseFragment
                setVisiable(true)//设置新fragment可见
            }
        })
		Timber.d("**onCreate()----mCurrentFragment=$mCurrentFragment")
    }

    override fun onResume() {
        super.onResume()
        setVisiable(true)
		Timber.d("**onResume")
    }

    override fun onPause() {
        super.onPause()
        setVisiable(false)
    }
	override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
        super.onRestoreInstanceState(savedInstanceState)
        Timber.d("**onRestoreInstanceState")
    }
    //对当前fragment可见性操作
    private fun setVisiable(visible: Boolean) {
        mCurrentFragment?.setVisiable(visible)
		Timber.d("**setVisiable(visible)----mCurrentFragment=$mCurrentFragment")
    }
}

2、BaseFragment代码如下:(OneFragment、TwoFragment继承该Fragment)

class BaseFragment : Fragment(){
    
    private var mAdapter: OrderAdapter? = null
    private var mIsVisiable = false//页面是否可见

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        context?.let { it ->
            mAdapter = OrderAdapter(it, mDatas, R.layout.adapter_order_item, mPresenter)
            getListView().adapter = mAdapter
			//解决setVisiable为可见方法执行在mAdapterc初始化前导致不刷新问题
            if (mIsVisiable) {
                loadData()
            }
        }
		Timber.d("**onViewCreated()----Fragment=$this----mIsVisiable=$mIsVisiable")
    }

    fun setVisiable(isVisiable: Boolean) {
        mIsVisiable = isVisiable
        mAdapter?.let {//onViewCreated未执行时mAdapter为空
            if (isVisiable ) {
                loadData()
            }
        }
		Timber.d("**setVisiable($isVisiable)----OneFragment=$this")
    }
	
	override fun onViewStateRestored(savedInstanceState: Bundle?) {
        super.onViewStateRestored(savedInstanceState)
		Timber.d("**onViewStateRestored()----Fragment==$this")
    }

    fun loadData() {
        //省略加载数据代码
    }

    fun showOrderListResult(orderListRes: OrderListRes?) {
        //省略获取数据后显示代码
    }

}

3、问题重现时日志信息如下:

分析:发现在TestActivity中当前的fragment为“fb806d66-21ce-44d0-805f-cb770f6b5230”,而ViewPager恢复的当前fragment是“330ee00e-519c-469f-a6b5-544ae97a0ba6”,当前展示的正是ViewPager缓存的这个Fragment,而TestActivity只是实例化并没有添加到ViewPager中,所以在对TestActivity中的fragmentsetVisiable()操作都不会显示

原理:当页面恢复时虽然在onCreate中创建了新的Fragment实例,然而ViewPager缓存机制会判断是否缓存当前Item的fragment如果存在则不再add,从而新创建的fragment不会显示,另外如果页面回收前展示的是TwoFragment则恢复时展示的也是TwoFragment,并且回调OnPageChangeListener,如果在oncreate中注册该监听则会执行该回调。

解决方案:在oncreate方法中判断如果是恢复状态则不再创建新fragment实例,而是用supportFragmentManager中已经缓存的,这样后续操作都是对当前ViewPager里的fragment了,代码如下:

class TestActivity : BaseActivity() {
    private val mFragmetList = mutableListOf<BaseFragment>()
	private var mCurrentIndex = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_me_order)
        initView(savedInstanceState)
    }

    private fun initView(savedInstanceState: Bundle?) {
	    if(savedInstanceState != null && supportFragmentManager.fragments.size > 0){
		    supportFragmentManager.fragments.forEach {
                mFragmetList.add(it)
            }
            mCurrentIndex = savedInstanceState.getInt("current_index")
		}else{
		    mFragmetList.add(OneFragment())
	        mFragmetList.add(TwoFragment())
			setListener()
		}
        viewPager.adapter = ViewPagerAdapter(supportFragmentManager, mFragmetList)
		Timber.d("**onCreate()----mCurrentFragment=$mFragmetList[mCurrentIndex]")
    }

    override fun onResume() {
        super.onResume()
        setVisiable(true)
		Timber.d("**onResume")
    }

    override fun onPause() {
        super.onPause()
        setVisiable(false)
    }
	
	override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt("current_index", mCurrentIndex)
    }
	
	override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
        super.onRestoreInstanceState(savedInstanceState)
		setListener()
        Timber.d("**onRestoreInstanceState")
    }
	
	
    //对当前fragment可见性操作
    private fun setVisiable(visible: Boolean) {
	    (mFragmetList[mCurrentIndex] as? BaseFragment)?.setVisiable(visible)
		Timber.d("**setVisiable(visible)----mCurrentFragment=$mFragmetList[mCurrentIndex]")
    }
	
	private fun setListener(){
	    viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
            override fun onPageScrollStateChanged(p0: Int) {}

            override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {}

            override fun onPageSelected(p0: Int) {
                setVisiable(false)//设置当前fragment不可见
				mCurrentIndex = p0
                setVisiable(true)//设置新fragment可见
            }
        })
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值