سؤال

I'm using a FragmentStatePagerAdapter in order to display fragments within a ViewPager, all of these Fragments obey the same layout container(a FrameLayout) but it's number is changeable over run-time, So that I put all of them into a static List of fragments and pass that list to the FragmentStatePagerAdapter(first time through it's constructor and each time after that I just update the list and notifydatasetchanged):

public class MyPageAdapter extends FragmentStatePagerAdapter {

    public static List<Fragment> myFragments = new ArrayList<Fragment>();
    public MyPageAdapter(FragmentManager fragmentManager, List<Fragment> fragments) {
        super(fragmentManager);

        myFragments = fragments;

    }

    public Fragment getItem(int i) {

        return myFragments.get(i);

    }

    @Override
    public int getCount() {

         return myFragments.size();

    }

}

Now this is the way I create a Fragment List during the run-time by:

public List<Fragment> fragmenting(int num) { // num: the Number of fragments i wanna create 

        List<Fragment> fragments = new Vector<Fragment>();

        for(int i =0; i < num ; i++){
            Bundle page = new Bundle();
            page.putInt("index", i);
            fragments.add(Fragment.instantiate(mContext, MyFragment.class.getName(), page));
        }

        return fragments;

}

and to commit the new Fragments to the ViewPager:

public static PagerAdapter ad;
public static ViewPager sViewPager;
private static MyPageAdapter mpa;

public void display_fragments(int i, boolean init) {

    if(init){ // init means we are in the first initialization and it goes here only at the first time
        List<Fragment> fragments = fragmenting(i);
        mpa = new MyPageAdapter(getChildFragmentManager(), fragments);
        sViewPager = (ViewPager) view.findViewById(R.id.my_view_pager);
    }else{ // is our case here
        List<Fragment> fragments = fragmenting(i);
        MyPageAdapter.myFragments = fragments;
        mpa.notifyDataSetChanged();
    }

    ad = mpa;
    sViewPager.setAdapter(ad);
    sViewPager.setCurrentItem(0);

}

at this stage everything in OK, and if I go and navigate through the specifid num of fragments it will navigate efficiently with each fragment has the container of MyFragment fragment.

but when trying to access the Views of the fragments, It returns the specified View (FrameLayout) according to MyFragment in the first two fragments only and after that it returns null, I tried to print out the returned Views by looping through mpa :

for(int g =0; g < mpa.getCount(); g++){
    System.out.println(mpa.getItem(g));
}

and this is what I got:

05-12 08:36:10.175: I/System.out(1062): MyFragment{53535b8c #1 id=0x7f06005e}
05-12 08:36:10.175: I/System.out(1062): MyFragment{540e71b4 #0 id=0x7f06005e}
05-12 08:36:10.175: I/System.out(1062): MyFragment{540e7298}
05-12 08:36:10.175: I/System.out(1062): MyFragment{540e737c}
05-12 08:36:10.175: I/System.out(1062): MyFragment{540e7460}
هل كانت مفيدة؟

المحلول

It returns the specified View (FrameLayout) according to MyFragment in the first two fragments only and after that it returns null

The adapter is built to be efficient so it destroys the views of the fragments that can't be accessible right away(the accessible fragments would be the current visible one plus one on each side(for easy swipe), this holds unless you've used setOffscreenPageLimit()). In your case if you call that for loop when the current page is 0 you'll get valid fragment views for only page 0 and 1. Calling setCurrentItem() doesn't work because the transition doesn't happen right away(so the other fragments are not built right away).

I don't know what you're trying to do with the views of the fragments, but you'll need to rethink your approach. You shouldn't be trying to update them like you do now anyway, you should look to update the fragments that are available to the user right away(the ones I mention above). Updating the views of the other fragments doesn't make sense as the user might not use them at all which would be wasteful.

You're doing other things wrong in your code like:

That adapter based on a list of fragments is bound to fail because you'll lose the proper references of the fragments. The adapter doesn't call the getItem() method every time, in some cases it will recreate the fragments on its own making you list fragment reference invalid(especially as you declared the list of fragments as static). If you're going to use a list make sure you keep the references to the fragments in order(for example you could get references to the actual fragments used in the instantiateItem() method of the adapter).

Don't make every class field static like you did. You shouldn't declare view fields as static because they hold a reference to the Context and you risk leaking it. The fragment list shouldn't be made static because the fragment where the adapter is used might get recreated, in this case the adapter itself will be recreated, your list however will hold the old content.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top