ViewPager的前两页正在消失,getItem()未被调用

时间:2014-08-03 20:45:51

标签: android android-fragments android-viewpager

上下文:

我正在制作音乐播放器,而我正在制作迷你图层。 miniplayer存在于ViewPager中,还有一个用于随机播放的浮动操作按钮(FAB)。最初,屏幕上只显示FAB。单击FAB时,音乐播放开始,Fab-Miniplayer ViewPager的页面计数从1到2,其页面设置为第二页,即miniplayer所在的页面。第二页中的miniplayer本身是一个垂直的viewpager,因此可以滑动到不同的歌曲。 miniplayer / vertical viewpager由PagerAdapter支持,该PagerAdapter从SongQueue obejct获取歌曲。

问题:

如果我点击FAB一次,那么miniplayer就会打开,一切正常。然后我通过向后滑动到ViewPager中的FAB页面来关闭miniplayer以停止播放。单击FAB开始播放并第二次打开miniplayer后,永远不会创建前两个片段。 miniplayer vertical ViewPager的PagerAdapter的getItem()方法永远不会被调用为项目0和项目1.在更高的层次上,miniplayer中的前两首歌曲没有显示出来。在进一步调查之后,onCreate()方法正在从最后一次打开miniplayer开始调用前两首歌曲,因此我猜测ViewPager正在实现某种缓存或者引用被持续的时间太长,因为miniplayer vertical viewpager认为它第二次实例化时已经有前两首歌。希望这个问题描述有意义。如果有任何问题,我会很乐意尝试进一步详细说明。

守则

SongsFragment

/**
 * Fragment used to display all of the songs on the device.
 */
public class SongsFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
    private static final String TAG = "SongsFragment";
    private SwipeListView mSwipeListView;
    private ViewPager fabMiniPlayerViewPager;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

        setHasOptionsMenu(true);

        // Initialize the loader to load the list of songs
        getLoaderManager().initLoader(SongCursorLoader.ALL_SONGS_ID, null, this);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.list_view_songs, parent, false);

        if (view != null) {
            mSwipeListView = (SwipeListView) view.findViewById(R.id.list_view_songs);
        }

        LinearLayout emptyView = (LinearLayout) inflater.inflate(R.layout.list_view_songs_empty, parent, false);

        mSwipeListView.setEmptyView(emptyView);

        fabMiniPlayerViewPager = (ViewPager) view.findViewById(R.id.fab_miniplayer_ViewPager);
        Integer viewPagerPageCount = new Integer(1);
        fabMiniPlayerViewPager.setTag(viewPagerPageCount);  // The fabMiniPlayerViewPager gets it's page count from the tag so it can be dynamically modified 
        fabMiniPlayerViewPager.setAdapter(new FragmentStatePagerAdapter(getChildFragmentManager()) {
            @Override
            public Fragment getItem(int i) {
                if (i == 0) {
                    // ShuffleFabFragment just houses a single button, the code is below
                    ShuffleFabFragment fragment = new ShuffleFabFragment();
                    fragment.setViewPager(fabMiniPlayerViewPager);
                    return fragment;
                }

                MiniPlayerFragment fragment = new MiniPlayerFragment();
                return fragment;
            }

            @Override
            public int getCount() {
                Integer count = (Integer) fabMiniPlayerViewPager.getTag();
                return count.intValue();
            }
        });

        fabMiniPlayerViewPager.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                // Pass touch events to the list view behind it
                mSwipeListView.onTouchEvent(motionEvent);
                return false;
            }
        });

        return view;
    }


    @Override
    public void onResume() {
        super.onResume();

        if (!MusicPlayerService.isStopped()) {
            Integer viewPagerPageCount = 2;
            fabMiniPlayerViewPager.setTag(viewPagerPageCount);
            PagerAdapter adapter = fabMiniPlayerViewPager.getAdapter();
            fabMiniPlayerViewPager.setAdapter(adapter);
            fabMiniPlayerViewPager.setCurrentItem(1, false);
        } else {
            Integer viewPagerPageCount = 1;
            fabMiniPlayerViewPager.setTag(viewPagerPageCount);
            fabMiniPlayerViewPager.getAdapter().notifyDataSetChanged();
        }
    }

}

ShuffleFabFragment

/**
 * Fragment representing the Shuffle Floating Action Button. On FAB click, it turns on shuffle and
 * plays a random song. Depending on the user preference, the mini-player will appear or the
 * Now Playing view will appear. The ShuffleFabFragment holds a reference to its containing
 * ViewPager so it can do the following:
 * <p/>
 * 1. Add the MiniPlayer fragment to the ViewPager to enable swiping & animations
 * 2. Remove the MiniPlayer fragment when it is swiped away
 * <p/>
 * Once the MiniPlayer is swiped away (to the right), it stops music playback.
 */
public class ShuffleFabFragment extends Fragment {
    private static final String TAG = "ShuffleFabFragment";
    private ViewPager fabMiniPlayerViewPager;

    public void setViewPager(ViewPager viewPager) {
        fabMiniPlayerViewPager = viewPager;
        fabMiniPlayerViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i2) {

            }

            @Override
            public void onPageSelected(int i) {
                if (i == 0) { // MiniPlayer swiped away
                    Integer viewPagerPageCount = new Integer(1);
                    fabMiniPlayerViewPager.setTag(viewPagerPageCount);
                    PagerAdapter adapter = fabMiniPlayerViewPager.getAdapter();
                    Intent stopMusicIntent = new Intent(getActivity(), MusicPlayerService.class);
                    stopMusicIntent.setAction(MusicPlayerService.ACTION_STOP);
                    getActivity().startService(stopMusicIntent);
                    fabMiniPlayerViewPager.setAdapter(adapter);
                }
            }

            @Override
            public void onPageScrollStateChanged(int i) {

            }
        });
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.shuffle_fab, viewGroup, false);

        ImageView shuffleFabImageView = (ImageView) view.findViewById(R.id.shuffle_fab_ImageView);
        shuffleFabImageView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                switch (motionEvent.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                    case MotionEvent.ACTION_MOVE:
                        // Scale up on touch to make the button appear to come closer
                        view.setScaleX(8f / 7f);
                        view.setScaleY(8f / 7f);
                        break;
                    case MotionEvent.ACTION_UP:
                        view.setScaleX(1f);
                        view.setScaleY(1f);
                        break;
                    default:
                        view.setScaleX(1f);
                        view.setScaleY(1f);
                }

                return false;
            }
        });

        shuffleFabImageView.setClickable(true);
        shuffleFabImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String shuffleMode = PreferencesHelper.getShuffleMode(getActivity());

                if (shuffleMode.equals(PreferencesHelper.SHUFFLE_MODE_OFF)) {
                    PreferencesHelper.setShuffleMode(getActivity(), PreferencesHelper.SHUFFLE_MODE_SMART);
                }

                SongQueue.initializeQueue(null, true, Song.COLLECTION_TYPE_ALL_SONGS, getActivity().getApplicationContext(), null);
                Song firstSong = SongQueue.getSong(0);
                firstSong.play(getActivity(), false);

                // On Click, update the page count, then set page to miniplayer
                Integer viewPagerPageCount = new Integer(2);
                fabMiniPlayerViewPager.setTag(viewPagerPageCount);
                fabMiniPlayerViewPager.getAdapter().notifyDataSetChanged();
                fabMiniPlayerViewPager.setCurrentItem(1, true);
            }
        });

        return view;
    }
}

MiniPlayerFragment

/**
 * Hosts MiniplayerCardFragments and allows for song skipping
 */
public class MiniPlayerFragment extends Fragment implements ViewPager.OnPageChangeListener {
    VerticalViewPager miniplayerCardViewPager;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.view_pager_miniplayer, viewGroup, false);

        miniplayerCardViewPager = (VerticalViewPager) view.findViewById(R.id.miniplayer_cards_ViewPager);
        miniplayerCardViewPager.setAdapter(new FragmentStatePagerAdapter(getChildFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                Song song = SongQueue.getSong(position);
                return MiniPlayerCardFragment.newInstance(song);
            }

            @Override
            public int getCount() {
                return SongQueue.getTotalSize();
            }
        });

        miniplayerCardViewPager.setOnPageChangeListener(this);

        SongQueue.addOnQueueChangeListener(new SongQueue.OnQueueChangeListener() {
            @Override
            public void onNextSongChanged() {
                onQueueChanged();
            }

            @Override
            public void onQueueChanged() {
                // Force re-layout to update fragments
                int queuePosition = SongQueue.getQueuePositionCurrentSong();
                PagerAdapter adapter = miniplayerCardViewPager.getAdapter();
                miniplayerCardViewPager.setAdapter(adapter);
                miniplayerCardViewPager.setCurrentItem(queuePosition, true);
            }

            @Override
            public void onCurrentSongChanged() {
                onQueueChanged();
            }
        });

        return view;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {
        int queuePosition = SongQueue.getQueuePositionCurrentSong();

        if (queuePosition < position) {
            Intent nextIntent = new Intent(getActivity(), MusicPlayerService.class);
            nextIntent.setAction(MusicPlayerService.ACTION_NEXT);
            getActivity().startService(nextIntent);
        } else if (queuePosition > position) {
            Intent prevIntent = new Intent(getActivity(), MusicPlayerService.class);
            prevIntent.setAction(MusicPlayerService.ACTION_PREV);
            getActivity().startService(prevIntent);
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }

    @Override
    public void onResume() {
        super.onResume();

        // Force re-layout to update fragments
        int queuePosition = SongQueue.getQueuePositionCurrentSong();
        PagerAdapter adapter = miniplayerCardViewPager.getAdapter();
        miniplayerCardViewPager.setAdapter(adapter);
        miniplayerCardViewPager.setCurrentItem(queuePosition, true);
        SongQueue.setPagerAdapter(adapter);
    }
}

Screenshots to help visualization

2 个答案:

答案 0 :(得分:0)

  

单击FAB开始播放并第二次打开miniplayer后,永远不会创建前两个片段。对于项目0和项目1,永远不会调用miniplayer垂直ViewPager的PagerAdapter的getItem()方法。

这是因为标准ViewPager已经有第0页和第1页。为了澄清Sanket的答案,setOffscreenPageLimit()表示要创建当前页面任意一侧的页数(通过{ {1}})和缓存,最小值为1.将忽略对getItem()的调用。

setOffscreenPageLimit(0) 是一种在用户切换页面时查找的方法。 A PageChangeListener是您查找用户切换页面的方法。

  

miniplayer vertical viewpager认为它第二次实例化时已经有前两首歌了

它没有第二次实例化AFAICT。

答案 1 :(得分:-1)

ViewPager默认为offScreenPageLimit值为3 ..所以它可能没有第二次加载你的前2项..

试试这个

mViewPager.setOffscreenPageLimit(0);

更多info