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的引用,进而调用他的方法去获得参数
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容