0

I have an app that needs to present a quick-start set of instructions for using a companion HW product. The instructions are simple fragment with a ViewPager that scrolls through four fragments with an image in them. The first time I instantiate the fragment with he viewpager, I see it's calls to get instantiated, then two calls to get the fragment for page 1 and page 2, and everything works as expected. Then, after hitting the back button to go back to the main app, and bringing up the instructions again, I see the calls to instantiate the fragment with the ViewPager, but no calls to get page 1 and page 2, so the screen is blank.

If I then scroll to page 2 (also blank), I'll see a call to get page 3 (Android is clearly queuing it up). Then I scroll to page 3 which shows up. Then I swipe back to page 2 which is still blank, but then there's a call to get page 1 so when I go back to page 1, it finally shows up.

I can't figure out why the new fragment with the ViewPager doesn't get calls to get pages 1 and 2 when it's instantiated the second time. It seems like it has state associated with it that isn't getting restored, but it should be a new instantiation.

Any help is greatly appreciated!

Here's the code for my fragment with the ViewPager:

public class InstructionsFragment extends Fragment { private static final String TAG = "InstructionsFragment";

public InstructionsFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    Log.d(TAG, "onCreate: " + savedInstanceState);
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    Log.d(TAG, "onCreateView: " + savedInstanceState);
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_instructions, container, false);

    // use support.v4 ViewPager, but support.v13 FragmentPagerAdapter
    // ViewPager is only in v4, but v13 FragmentPagerAdapter doesn't require support fragments
    android.support.v4.view.ViewPager viewPager = (android.support.v4.view.ViewPager) view.findViewById(R.id.viewPager);
    viewPager.setAdapter(new android.support.v13.app.FragmentPagerAdapter(getFragmentManager())  {
        @Override
        public Fragment getItem(int position) {
            Log.d(TAG, "getItem: " + position);
            switch(position) {
                case 0: return ImageFragment.newInstance(R.drawable.instructions0);
                case 1: return ImageFragment.newInstance(R.drawable.instructions1);
                case 2: return ImageFragment.newInstance(R.drawable.instructions2);
                default: return ImageFragment.newInstance(R.drawable.instructions3);
            }
        }

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

    });

    return view;
}

}

and here's the code for the fragment that shows an image:

public class ImageFragment extends Fragment {
private static final String TAG = "ImageFragment";
private static final String ARG_IMAGE_RESOURCE_ID = "imageResourceId";
private int mImageResourceID;


public ImageFragment() {
    // Required empty public constructor
}

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 */
// TODO: Rename and change types and number of parameters
public static ImageFragment newInstance(int imageResourceID) {
    ImageFragment fragment = new ImageFragment();
    Bundle args = new Bundle();
    args.putInt(ARG_IMAGE_RESOURCE_ID, imageResourceID);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mImageResourceID = getArguments().getInt(ARG_IMAGE_RESOURCE_ID);
    }
    Log.d(TAG, "onCreate, imageResourceID = " + mImageResourceID);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    Log.d(TAG, "onCreateView, imageResourceID = " + mImageResourceID);

    View view = inflater.inflate(R.layout.fragment_image, container, false);

    ImageView imageView = (ImageView)view.findViewById(R.id.imageView);
    imageView.setImageResource(mImageResourceID);

    return view;
}
@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    Log.d(TAG, "onSaveInstanceState, imageResourceID = " + mImageResourceID);
    outState.putInt(ARG_IMAGE_RESOURCE_ID, mImageResourceID);
}

}

Jon
  • 462
  • 5
  • 14

2 Answers2

2

You are using fragments inside fragments, so you must use getChildFragmentManager() method instead of getFragmentManager() or getSupportFragmentManager().

Try this:

viewPager.setAdapter(new android.support.v13.app.FragmentPagerAdapter(getChildFragmentManager())  {
    @Override
    public Fragment getItem(int position) {
        Log.d(TAG, "getItem: " + position);
        switch(position) {
            case 0: return ImageFragment.newInstance(R.drawable.instructions0);
            case 1: return ImageFragment.newInstance(R.drawable.instructions1);
            case 2: return ImageFragment.newInstance(R.drawable.instructions2);
            default: return ImageFragment.newInstance(R.drawable.instructions3);
        }
    }

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

});

If you need more info about this behavior you can read the official Fragment doc https://developer.android.com/reference/android/app/Fragment.html and https://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager(). Also you can check this answer for a explanation : https://stackoverflow.com/a/14775322/5658915

Jonathan Aste
  • 1,764
  • 1
  • 13
  • 20
1

on the below code you are using getFragmentManager(), but here you should use getChildFragmentManager() because you are using a ViewPager in Fragment.

viewPager.setAdapter(newandroid.support.v13.app.FragmentPagerAdapter(getFragmentManager())  {
        @Override
        public Fragment getItem(int position) {
            Log.d(TAG, "getItem: " + position);
            switch(position) {
                case 0: return ImageFragment.newInstance(R.drawable.instructions0);
                case 1: return ImageFragment.newInstance(R.drawable.instructions1);
                case 2: return ImageFragment.newInstance(R.drawable.instructions2);
                default: return ImageFragment.newInstance(R.drawable.instructions3);
            }
        }
Aniruddh Parihar
  • 3,072
  • 3
  • 21
  • 39
  • Thanks Aniruddh. The only reason I accepted the other answer was because of the info links at the bottom. But your both right for the same reason. – Jon May 30 '17 at 17:27