RecyclerView in FragmentPagerAdaper only updates when screen is rotated

1.8k views Asked by At

I have a fragment in a FragmentPagerAdpater. The Fragment is basically a RecyclerView. The source for the RecyclerView is provided by a Loader which is inside the Fragment.

My problem is that the list appears empty when it is first instantiated. But when I rotate the screen, it appears fine.

Do you have any idea what could go wrong? I am happy to provide some (or a lot) of code if needed. Just tell me which parts you want to see.

Here is the code from the parent activity:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

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

    @Override
    public Fragment getItem(int i) {
        switch (i) {
            case 0:
                //We return an instance of the RouteListFragment
                RouteListFragment frag = RouteListFragment.getInstance(session.getId());
                return frag;
            case 1:
                //We return an instance of the RouteSpotListFragment
                RouteSpotListFragment frag2 = RouteSpotListFragment.getInstance(sessionSpot.getId());
                return frag2;
            default :
                return null;
        }

    }

The main methods from the Fragment:

public static RouteListFragment getInstance (int sessionId){
    RouteListFragment frag = new RouteListFragment();
    Bundle bundle = new Bundle ();
    bundle.putInt(SESSION_ID, sessionId);
    frag.setArguments(bundle);
    return frag;
}

/* (non-Javadoc)
 * @see android.app.Fragment#onCreate(android.os.Bundle)
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    //We extract the RouteList from the Bundle
    Bundle bundle = getArguments();
    sessionId = bundle.getInt(SESSION_ID);

    //We create a MyRouteListAdapter with a null cursor
    Cursor cursor = null;
    routeListAdapter = new MyRouteListAdapter(cursor, getActivity());
    updateList();

    super.onCreate(savedInstanceState);
}

/* (non-Javadoc)
 * @see android.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
 */
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    //Inflate the layout
    layout = (RelativeLayout) inflater.inflate(R.layout.fragment_route_list, container, false);

    routeSource = new RouteDataSource (getActivity());

    //Now that we have the routeSource, we can prepare the routeListAdapter
    routeRecyclerList = (RecyclerView) layout.findViewById(R.id.route_list_view);
     // use a linear layout manager
    mLayoutManager = new LinearLayoutManager(getActivity());
    routeRecyclerList.setLayoutManager(mLayoutManager);

    routeRecyclerList.setAdapter(routeListAdapter);

    return layout;
}

    public void updateList(){
    /*
     * we get the loaderManager to start the query
     * If a Loader has already been initiated, we need to reload it. Otherwise the 
     * onCreateLoader callback method will not be called
     * Else, we initiate a Loader
     */
    LoaderManager manager = getLoaderManager();
    if (manager.getLoader(LOADER_GET_ALL_ROUTES)!= null)    
        manager.restartLoader(LOADER_GET_ALL_ROUTES, null, this);
    else manager.initLoader(LOADER_GET_ALL_ROUTES, null, this);

}

Finally, I swap the cursor in the onLoadFinished() callback method as part of the LoaderManager.Callback methods.

EDIT: I just realized that if I wait for the LoaderManager to finish loading (1-2 seconds), before swiping the the Fragment which holds the Loader, the content is displayed.

I don't know if that new info changes anything. I am still very much stuck and definitely need help.

2

There are 2 answers

0
JDenais On BEST ANSWER

I finally solved my problem and here is how :

1 - Change FragmentPagerAdapter to FragmentStatePagerAdapter. The reason for that is that FragmentPagerAdapter does not recreate your Fragments if needed. It keeps everything in memory. So if your Fragment is not fully operational when it is created, or if you want to refresh it later on, you are in trouble.

2 - Remove the LoaderManager structure from the Fragments and let the parent Activity deal with querying the database. This way, I could have the FragmentStatePagerAdapter instantiate an empty fragment at first, and then the activity could tell the adapter to recreate the Fragment once the query has returned. And for this re-creation, I needed the FragmentStatePagerAdapter.

3 - Overide the getItemPosition() of my FragmentStatePagerAdapter so that all the Fragments get recreated when I call notifyDataSetChanged() on the PagerAdapter:

public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

Because my fragments are not too complex and the data to load is not big, I don't mind recreating all the fragments I have. Therefore using POSITION_NONE is ok performance wise.

I hope this little findings can help other people. =)

5
Moinkhan On

move super.onCreate(savedInstanceState) to the first line...

Why it works ..?

In your code you have put super.onCreate() to end of the method. and you have apply your code first. So you are forcing the android to stop their default implementation of onCreate() which is bad one. Because in their method they are doing all initialization and UI related task.

So it's better to call super() always at the first line.

I hope you understand.