Search code examples
androidandroid-fragmentsandroid-viewpagerandroid-framelayoutandroid-nested-fragment

Cannot get pager working with child fragments


I have a view pager activity in an android app that I want to use to navigate a collection of typed objects. The first one loads fine, but when you swipe to navigate, the content of the child fragment doesn't get repopulated. Code as follows.

Ps - if you look at the last XML file below, you can see what is being used as the pager source fragment. All the other buttons re-appear fine as you re-page. It is only the FrameLayout child frame that doesn't reload.

public class FindActivity
{
    ...
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_find);

        ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);

        ArrayList<MyItem> items = new ArrayList<MyItem>();
        items.add(new MyItem("James", 34, "London", R.drawable.profile, R.drawable.camera, "What does this photo make you think of?", R.drawable.ocean));

        mCollectionPagerAdapter = new CollectionPagerAdapter(getApplicationContext(), getFragmentManager(), items);

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mCollectionPagerAdapter);
                 ....
    }

public class CollectionPagerAdapter extends FragmentStatePagerAdapter {

    private ArrayList<MyItem> items;
    private Context context;

    public CollectionPagerAdapter(Context context, FragmentManager fm, ArrayList<MyItem> itemCollection) 
    {
        super(fm);
        items = itemCollection;
        this.context = context;
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment = new MyItemPagerFragment(context);
        Bundle args = new Bundle();

        args.putString(MyItemPagerFragment.ARG_USERNAME, items.get(position).Name);
        args.putInt(MyItemPagerFragment.ARG_AGE, items.get(position).Age);
        args.putString(MyItemPagerFragment.ARG_LOCATION, items.get(position).Location);
        args.putInt(MyItemPagerFragment.ARG_PROFILEIMAGE, items.get(position).ProfileImage);
        args.putInt(MyItemPagerFragment.ARG_GENREIMAGE, items.get(position).GenreImage);
        args.putString(MyItemPagerFragment.ARG_DESCRIPTION, items.get(position).Description);
        args.putInt(MyItemPagerFragment.ARG_CONTENTIMAGE, items.get(position).ContentImage);

        fragment.setArguments(args);
        return fragment;
    }

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

    @Override
    public CharSequence getPageTitle(int position) {
        return "Item: " + items.get(position).Name;
    }
}

public class MyItemPagerFragment extends Fragment {
    public static final String ARG_USERNAME = "name";
    public static final String ARG_AGE = "age";
    public static final String ARG_LOCATION = "location";
    public static final String ARG_PROFILEIMAGE = "profileimage";
    public static final String ARG_GENREIMAGE = "genreimage";
    public static final String ARG_DESCRIPTION = "description";
    public static final String ARG_CONTENTIMAGE = "contentimage";

    private Context context;

    public MyItemPagerFragment(Context context)
    {
        this.context = context;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    {
        View rootView = inflater.inflate(R.layout.fragment_find, container, false);
        Fragment fragment = new ItemFragment(
                getArguments().getString(ARG_USERNAME),
                getArguments().getInt(ARG_AGE),
                getArguments().getString(ARG_LOCATION),
                context.getResources().getDrawable(getArguments().getInt(ARG_PROFILEIMAGE)),
                context.getResources().getDrawable(getArguments().getInt(ARG_GENREIMAGE)),
                getArguments().getString(ARG_DESCRIPTION),
                context.getResources().getDrawable(getArguments().getInt(ARG_CONTENTIMAGE)));

        FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.find_content, fragment).commit();

        return rootView;
    }
}

And fragment_find.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="lakecrest.FindActivity$PlaceholderFragment" >

    <FrameLayout
        android:id="@+id/find_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
            android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
    />

    <LinearLayout
        android:layout_below="@id/find_content"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">   

        <ImageButton 
            android:id="@+id/sendmessage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/button_startconversation"
            style="?android:attr/borderlessButtonStyle" />

    </LinearLayout>

    <LinearLayout
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">   

        <ImageButton
            android:id="@+id/addtobasket"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/button_basket"
            style="?android:attr/borderlessButtonStyle" />

        <ImageButton 
            android:id="@+id/notinterested"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_cancel"
            style="?android:attr/borderlessButtonStyle"/>

   </LinearLayout>

</RelativeLayout>

Solution

  • I presume that ItemFragment and MyItemPagerFragment are two different fragment types, with the former nested inside the latter.

    In that case, try this: in the onCreateView() method of your MyItemPagerFragment class, replace

    FragmentManager fragmentManager = getFragmentManager();
    

    with

    FragmentManager fragmentManager = getChildFragmentManager();
    

    First test your app with this modification. If you experience an IllegalStateException getting thrown, then add the following code to your MyItemPagerFragment class:

    @Override
    public void onDetach() {
        super.onDetach();
    
        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);
    
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
    

    If you don't experience any crashes after the first modification, then ignore the second one.