ViewPager和Fragment的一个实例坑

这里主要涉及到Fragment在ViewPager中显示时,一个同步和异步的问题。

这样一个场景:
你做一个播放音乐的App,在界面底部有一个控制栏可以开始\暂停音乐的播放,点击控制栏可以进入播放详情。假设你刚好点击了播放,然后再进入播放详情页面(Activity实现),你希望一进去会有一个动画效果,这个动画在Fragment里面实现。里面由ViewPager+Fragment实现,左右滑动可切换歌曲。

也许会有下面的代码

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {
                    getCur_fragment().startRotate();  //开始动画
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

要执行动画,那么界面必须出来,这么做,动画肯定不会执行,因为界面还没出来。

那么,Fragment的界面时什么时候出来的呢?

ViewPager的populate()方法

        public void populate(){
        //.......
        mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
        mAdapter.finishUpdate(this);   //FragmentPageAdapter进行了重写
        }
 @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitNowAllowingStateLoss();
            mCurTransaction = null;
        }
    }

FragmentPageAdapter重写了该方法,也就是去执行Fragment栈中所有操作(mCurTransaction.add(container.getId(), fragment);),而执行栈中的操作commitNow是一个同步任务。也就是说,此时Fragment才被attach到Activity中,Fragment中的View才被添加到ViewPager中。

现在问题在于,当监听器中的onPageSelected()方法执行的时候,ViewPager的populate()方法执行了吗?没有!

public void setCurrentItem(){
        if (mFirstLayout) {         //第一次布局,默认为true
            // We don't have any idea how big we are yet and shouldn't have any pages either.
            // Just set things up and let the pending layout handle things.
            mCurItem = item;
            if (dispatchSelected) {
                dispatchOnPageSelected(item);    //该方法执行
            }
            requestLayout();  //发送一个异步的布局消息
        } else {
            populate(item);
            scrollToItem(item, smoothScroll, velocity, dispatchSelected);
        }
}

也就是说,当你调用了setCurrentItem(),监听器的回调方法会同步执行,而populate()方法却要在下一个消息中执行。所以此时,Fragment的对象确实被创建出来了,他的生命周期方法却还没有执行。

解决方法:

  1. 在创建Fragment的时候,通过setArgument方法设置参数
  2. 在onAttach()中拿到Activity的引用,进而调用他的方法去获得参数

你可能感兴趣的:(ViewPager和Fragment的一个实例坑)