0

In my Android application I'm using a TabLayout with a FragmentStatePagerAdapter to show dynamically generated fragments. It shows correctly the fragments the first time, but when going back to some that are already viewed and are not the adjacent ones it shows a blank page...

I've looked into this and there seems to be two way of fixing this:

  • Using FragmentStatePagerAdapter instead of FragmentPagerAdapter, which I already did and it didn't change anything.

  • Change
    adapter = new FragmentStatePagerAdapter(*getSupportFragmentManager*());
    into:
    adapter = new FragmentStatePagerAdapter(*getChildFragmentManager*());
    that I can't do because I'm in AppCompatActivity and this method is in Fragment...

Is there a way to solve this issue without extending this activity out of FragmentActivity that would screw up other stuff in my project?

Code:

private class SubsPagerAdapter extends FragmentStatePagerAdapter {

    private final ArrayList<Fragment> fragmentsList = new ArrayList<>();
    private final ArrayList<String> titleList = new ArrayList<>();

    SubsPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return fragmentsList.get(position);
    }

    @Override
    public int getCount() {
        return fragmentsList.size();
    }

    void addFragment(Fragment fragment, String title) {
        fragmentsList.add(fragment);
        titleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return titleList.get(position);
    }

    @Override
    public Parcelable saveState() {
        return null;
    }
}

Implementation:

subsPager = (ViewPager) findViewById(R.id.subsPager);
                        tabLayout = (TabLayout) findViewById(R.id.tabs_view);

subsPager.setAdapter(adapter);
tabLayout.setupWithViewPager(subsPager)

Edit - Fragment Code:

public class PostsListFragment extends Fragment {

private ArrayList<CustomPost> posts;

private Sorting sorting;

private String name;
private RecyclerView recyclerView;
private SubPostsAdapter adapter;
private LinearLayoutManager linearLayoutManager;
private Fetcher fetcher

public PostsListFragment() {
    this.posts = new ArrayList<>();
}

public static Fragment newInstance(String name) {
    PostsListFragment pf = new PostsListFragment();
    pf.name = name;

    return pf;
}

@Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    recyclerView = (RecyclerView) inflater.inflate(R.layout.posts_list_holder, container, false);

    //default sorting
    this.sorting = Sorting.HOT;
    this.fetcher = new Fetcher(name);

    loadItems();

    return recyclerView;
}

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

private void loadItems() {
    if (posts.size() == 0) {
        new Thread() {
            @Override
            public void run() {
                posts.addAll(fetcher.fetchPosts(sorting));

                new Thread() {
                    @Override
                    public void run() {
                        linearLayoutManager = new LinearLayoutManager(recyclerView.getContext());

                        adapter = new SubPostsAdapter(posts, getActivity());

                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                recyclerView.setLayoutManager(linearLayoutManager);
                                recyclerView.setAdapter(adapter);
                            }
                        });

                    }
                }.start();
            }
        }.start();
    }
}
}
noamt
  • 7,397
  • 2
  • 37
  • 59
Luca Pellizzari
  • 324
  • 4
  • 12
  • What do you mean "shows a blank page"? 1) are you recreating a Fragment at any point? 2) can you show the code of an example Fragment that this happens to? A ViewPager stills calls the full life cycle of a Fragment, so if it's blank and going to download data, it'll do it again later – OneCricketeer Jan 24 '17 at 14:05
  • The fragment is only a recyclerview that displays text/images downloaded from a url based on a name string. – Luca Pellizzari Jan 24 '17 at 14:15
  • Your problem is `pf.name = name` is set as null when you swipe back to the Fragment. That's not how to set instance variables to Fragments – OneCricketeer Jan 24 '17 at 14:17
  • Possible duplicate of [Best practice for instantiating a new Android Fragment](http://stackoverflow.com/questions/9245408/best-practice-for-instantiating-a-new-android-fragment) – OneCricketeer Jan 24 '17 at 14:19
  • I don't think this is the problem because I just went in debug and the variable has the name in it, but the fragment is still blank – Luca Pellizzari Jan 24 '17 at 14:21
  • Secondly, I'm not sure what `fetcher.fetchPosts` does, but it looks like a blocking network call, and Android doesn't really like those. If you look at Volley or Okhttp for HTTP calls, you'll notice how they use callback methods to return results. Ideally, a low level `Thread` shouldnt need to be used – OneCricketeer Jan 24 '17 at 14:22
  • Just try `setArguments` since that's the correct pattern. Then, feel free to implement onResume method of the Fragment to call loadItems() again – OneCricketeer Jan 24 '17 at 14:24
  • Then, that inner Thread is pointless. All the methods there for the recyclerview can go in onCreateView. You can set an adapter and layout manager with an empty list. You just need to call notify dataset change method of the adapter in the first thread – OneCricketeer Jan 24 '17 at 14:27

1 Answers1

0

It was more stupid then it looked, removing this line:

 if (posts.size() == 0) {

from loadItems in the Fragment, makes it work as intended. Thanks to cricket_007 for the advices!

Community
  • 1
  • 1
Luca Pellizzari
  • 324
  • 4
  • 12