ViewPager 中的片段在其 RecyclerView 旋转时未显示任何内容

Fragment in ViewPager is not displaying anything in its RecyclerView on rotation(ViewPager 中的片段在其 RecyclerView 旋转时未显示任何内容)

本文介绍了ViewPager 中的片段在其 RecyclerView 旋转时未显示任何内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在与 TabLayout 集成的 ViewPager 中有 4 个片段.这些 Fragments 中的每一个都包含一个 RecyclerView,因为我正在显示未知数量的列表项.这些项目是按日期加载的,所以我有两个按钮可以让您更改日期,然后根据设置的日期加载列表项目中的相应数据.按钮是外部活动的一部分.

I have 4 Fragments in a ViewPager that is integrated with a TabLayout. Each of those Fragments holds a RecyclerView because I'm displaying an unknown amount of list items. The items are loaded by date, so I have two buttons that let you change days, and then the appropriate data in the list items is loaded based on the date that is set. The buttons are part of the outer activity.

到目前为止,一切都很完美,但是一旦我旋转设备,片段就不会加载任何东西.片段内不显示任何内容.不过,外部活动中的视图显示得很好.奇怪的是,如果我触摸其中一个更改日期的按钮,则会加载片段并正确显示数据.但是我需要在旋转后立即显示所有内容,而不仅仅是单击其中一个按钮时.这是我的代码:

Everything so far works perfectly BUT once I rotate the device the fragments don't load anything. Nothing is displayed inside the Fragments. The views in the outer activity are displayed fine though. The weird thing is that if I touch one of the buttons that changes the date, the Fragments are loaded and the data is displayed correctly. But I need everything to be displayed immediately after rotation not just when I click one of those buttons. Here is my code:

public class MainActivity extends AppCompatActivity implements DatePickerFragment.DateDialogInterface
{
    private final static String COLOR_CONTROL_CHOSEN = "color_control_chosen";
    private static final String DIALOG_DATE = "dialog_date";
    private static final String TAG = "MainActivity";
    private static final String SET_LOCATION = "set_location";
    public static final String LEAGUE_POSITION = "league_position";
    private Toolbar mToolbar;
    private ViewPager mViewPager;
    private TabLayout mTabLayout;
    private ImageButton mPrevDateButton, mNextDateButton;
    private TextView mDateTextView, mLeagueTextView;
    private String mTodaysDate;
    private Date mLastSelectedDate, mTodaysDateObj;
    private ProgressBar mProgressBar;
    private FragmentPagerAdapter mAdapterViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mToolbar = (Toolbar) findViewById(R.id.outnix_toolbar);
        mViewPager = (ViewPager) findViewById(R.id.main_activity_view_pager);
        mTabLayout = (TabLayout) findViewById(R.id.main_activity_tab_layout);
        mDateTextView = (TextView) findViewById(R.id.display_date_text_view);
        mLeagueTextView = (TextView) findViewById(R.id.league_title_header);
        mPrevDateButton = (ImageButton) findViewById(R.id.previous_date_button);
        mNextDateButton = (ImageButton) findViewById(R.id.next_date_button);
        mProgressBar = (ProgressBar) findViewById(R.id.loading_circle);
        mProgressBar.setVisibility(View.GONE);
        setTodaysDate();
        mDateTextView.setText("Today");

        setSupportActionBar(mToolbar);
        assert getSupportActionBar() != null;
        getSupportActionBar().setDisplayShowTitleEnabled(false);

        NavDrawerFragment navDrawerFrag = (NavDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_nav_drawer);
        navDrawerFrag.setUp((DrawerLayout) findViewById(R.id.nav_drawer), mToolbar);

        setUpViewPagerAdapterOnCreate();
        mTabLayout.setupWithViewPager(mViewPager);

        mDateTextView.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                FragmentManager fm = getSupportFragmentManager();
                DatePickerFragment dialog = new DatePickerFragment();
                Bundle args = new Bundle();
                args.putSerializable("ARG_DATE", mLastSelectedDate);
                dialog.setArguments(args);
                dialog.show(fm, DIALOG_DATE);
            }
        });

     THESE TWO LISTENERS ARE WHAT DISPLAY THE DATA AFTER A ROTATION CHANGE
     //////////////////////////////////////////////////////////////////
        mPrevDateButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                mProgressBar.setVisibility(View.VISIBLE);
                updateDate(-1);
                setupViewPagerAdapter(getViewPagerPos());
            }
        });

        mNextDateButton.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                mProgressBar.setVisibility(View.VISIBLE);
                updateDate(1);
                setupViewPagerAdapter(getViewPagerPos());
            }
        });
    }
    ////////////////////////////////////////////////////////////////////
/*  @Override
    protected void onResume()
    {
        super.onResume();
        setupViewPagerAdapter(getViewPagerPos());
    }*/

    private void setUpViewPagerAdapterOnCreate()    //only called when opened from LauncherActivity
    {
        setupViewPagerAdapter(0);

        int touchColorPixel = getIntent().getIntExtra(COLOR_CONTROL_CHOSEN, ContextCompat.getColor(this, R.color.blue));

        if(touchColorPixel == ContextCompat.getColor(this, R.color.orange))
            mViewPager.setCurrentItem(0);
        else if(touchColorPixel == ContextCompat.getColor(this, R.color.blue))
            mViewPager.setCurrentItem(1);
        else
            mViewPager.setCurrentItem(3);
    }

    private void setupViewPagerAdapter(int currentPos)
    {
        mAdapterViewPager = new MainPagerAdapter(getSupportFragmentManager());

        mViewPager.setAdapter(mAdapterViewPager);
        mViewPager.setOffscreenPageLimit(4);
        mViewPager.setCurrentItem(currentPos);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);
        outState.putSerializable(DIALOG_DATE, mLastSelectedDate);           //save the last date selected (or last date displayed) on rotation change.
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {
        super.onRestoreInstanceState(savedInstanceState);
        setDateFromDialog((Date) savedInstanceState.getSerializable(DIALOG_DATE));  //restore the last date selected to the new rotation change
    }

    public ProgressBar getProgressBar()
    {
        return mProgressBar;
    }

    @Override
    public void setDateFromDialog(Date date)
    {
        String newDate = getFormattedDate(date);
        updateTodaysDate();     
        mLastSelectedDate = date;

        setupViewPagerAdapter(getViewPagerPos());

        if(newDate.equals(mTodaysDate))
            mDateTextView.setText("Today");
        else
            mDateTextView.setText(newDate);
    }

    private int getViewPagerPos()
    {
        return mViewPager.getCurrentItem();
    }
}

mPrevDateButtonmNextDateButton 2 个按钮是单击修复"问题的按钮.在他们的点击监听器中, updateDate() 方法只做与 TextView 对象相关的事情,这就是我没有包含定义的原因(我试图让帖子尽可能短).所以我确定它与我的 setupViewPagerAdapter() 方法有关.我尝试在 onCreate()onResume() 中添加此方法,但 Fragments 仍然保持空白.

The 2 buttons mPrevDateButton and mNextDateButtonare the buttons that when clicked "fix" the problem. Inside their click listeners, the updateDate() method is only doing stuff related to a TextView object and is why I didn't include the definitions (I'm trying to keep the post as short as possible). So I know for sure it has something to do with my setupViewPagerAdapter() method. I've tried adding this method in onCreate() and onResume() but the Fragments still stay blank.

这是我的 ViewPager 适配器代码:

Here is my ViewPager adapter code:

public class MainPagerAdapter extends FragmentPagerAdapter
{
    private final String[] mFragmentTitleList = {"My Games", "All Games", "All Places", "My Places"};   //tab title names
    private final static int NUM_FRAGMENTS = 4;

    public MainPagerAdapter(FragmentManager fm)
    {
        super(fm);
    }

    @Override
    public Fragment getItem(int position)
    {
        switch(position)
        {
            case 0:
                return MyGamesFragment.newInstance();
            case 1:
                return AllGamesFragment.newInstance();
            case 2:
                return AllPlacesFragment.newInstance();
            case 3:
                return MyPlacesFragment.newInstance();
            default:
                return null;
        }
    }

    @Override
    public int getCount()
    {
        return NUM_FRAGMENTS;
    }

    @Override
    public CharSequence getPageTitle(int position)
    {
        return mFragmentTitleList[position];
    }
}

这是 4 个片段之一.它们几乎都有相似的设计.

Here is one of the 4 fragments. They pretty much all have similar design.

public class AllGamesFragment extends Fragment
{
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private RecyclerView mAllGamesRecyclerView;
    private GameAdapter mGameAdapter;
    private List<Game> mGameList = new ArrayList<>();
    private MainActivity mMainActivity;     //keeps a reference to MainActivity to access public methods

    public static AllGamesFragment newInstance()
    {
        return new AllGamesFragment();
    }

    @Override
    public void onAttach(Context context)
    {
        super.onAttach(context);
        mMainActivity = (MainActivity) context;
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        mMainActivity.getProgressBar().setVisibility(View.VISIBLE);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.recycler_view_all_games, container, false);
        mAllGamesRecyclerView = (RecyclerView) view.findViewById(R.id.all_games_recycler_view);
        mAllGamesRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh);
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener()
        {
            @Override
            public void onRefresh()
            {
                getGamesData();
                mSwipeRefreshLayout.setRefreshing(false);
            }
        });

        return view;
    }

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

    private void setupAdapter()
    {
        if(isAdded())
        {
            mGameAdapter = new GameAdapter(mGameList);
            mAllGamesRecyclerView.setAdapter(mGameAdapter);
        }
    }

    private void getGamesData()
    {
        new GetDataTask(mMainActivity.getLastSelectedDate()).execute();
    }

    private class GetDataTask extends Scraper.GameDataTask
    {
        GetDataTask(Date date)
        {
            super(date, getActivity());
        }

        @Override
        protected void onPostExecute(List<Game> games)
        {
            mGameList = games;
            setupAdapter();
            mMainActivity.getProgressBar().setVisibility(View.GONE);
        }
    }

    private class GameAdapter extends RecyclerView.Adapter<GameHolder>
    {
        private List<Game> mGames;

        public GameAdapter(List<Game> games)
        {
            mGames = games;
        }

        @Override
        public GameHolder onCreateViewHolder(ViewGroup parent, int viewType)
        {
            LayoutInflater inflater = LayoutInflater.from(getActivity());
            View view = inflater.inflate(R.layout.list_game_item, parent, false);
            return new GameHolder(view, getActivity());
        }

        @Override
        public void onBindViewHolder(GameHolder holder, int position)
        {
            holder.bindGameData(mGames.get(position));
        }

        @Override
        public int getItemCount()
        {
            return mGames.size();
        }
    }

我在这里查看了很多帖子,多次更改了我的代码,但我仍然无法让它工作.当我单击其中一个日期按钮时,我只是对它修复"感到困惑.如果您希望我发布更多代码,请告诉我.很抱歉这篇长文,但我觉得需要上下文.非常感谢任何帮助!

I've looked at so many posts on here, changed my code many times and I still can't get it to work. I'm just baffled that it "fixes" when I click one of the date buttons. If you would like me to post more code of something let me know. Sorry for the long post but I feel the context is needed. I really appreciate any help!

推荐答案

我想通了!我不得不切换到 FragmentStatePagerAdapter 而不是使用 FragmentPagerAdapter.我认为这与 Fragments 被销毁并重新创建有关.

I figured it out! I had to switch to a FragmentStatePagerAdapter rather than use a FragmentPagerAdapter. I believe it has something to do with the Fragments being destroyed and recreated again.

我还读到另一种方法是将 ViewPager 包装在 Fragment 中,并在创建其适配器时使用 getChildFragmentManager() 而不是 getSupportFragmentManager() 像这样:

I also read that another way would be to wrap the ViewPager in a Fragment and when you create its adapter you use getChildFragmentManager() rather than getSupportFragmentManager() like this:

mAdapterViewPager = new MyPagerAdapter(getChildFragmentManager());

我不想为了解决这个问题而在 ViewPager 周围添加整个 Fragment,所以我改用 FragmentStatePagerAdapter 并且它起作用了!希望这对其他人有帮助.

I didn't want to have to add an entire Fragment around my ViewPager just to fix this issue so I switched to using FragmentStatePagerAdapter and it worked! Hope this helps someone else out there.

这篇关于ViewPager 中的片段在其 RecyclerView 旋转时未显示任何内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:ViewPager 中的片段在其 RecyclerView 旋转时未显示任何内容