Fragment View in Viewpager Is Not Restored When Resuming

Fragment view in ViewPager is not restored when resuming

After a while ran into the same problem again, so updating this question.
If you're using FragmentStatePagerAdapter you should provide FragmentManager via getChildFragmentManager() instead of getFragmentManager(). See Issue 55068: ViewPager doesn't refresh child fragments when back navigation via backstack

Fragment in ViewPager not restored after popBackStack

After a lengthy investigation it turns out to be a problem with the fragment manager.

When using a construct like the one above the fragment transaction to reattach the fragment to the page list is silently discarded. It is basically the same problem that causes a

java.lang.IllegalStateException: Recursive entry to executePendingTransactions 

when trying to alter the fragments inside the FragmentPager.

The same solution, as for problems with this error, is also applicable here. When constructing the FragmentStatePagerAdapter supply the correct child fragment manager.

Instead of

    viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));

do

    viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getChildFragmentManager(),mParentString));

See also: github

ViewPager's Fragment's view lost when ViewPager's parent Fragment hidden then shown

You're not providing enough info for your specific issue, so I built a sample project that tries to reproduce your issue: the app has an activity that holds a fragment (PagerFragment) within a relative layout and below this layout I have a button that hides & shows above PagerFragment. PagerFragment has a ViewPager and each fragment within pager adapter simply displays a label - this fragment is named DataFragment. The label list is created in parent activity and passed to PagerFragment and then through its adapter to each DataFragment. Changing the PagerFragment visibility is done with no issues and each time it's becoming visible again it shows the previous shown label.

The key of the issue:
Use Fragment#getChildFragmentManager() when you're creating the viewpager adapter and not getFragmentManager!

Maybe you can compare this simple project with what you have and check where are the differences. So here goes (top-down):

PagerActivity (the only activity in the project):

public class PagerActivity extends FragmentActivity {

private static final String PAGER_TAG = "PagerActivity.PAGER_TAG";

@Override
protected void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.pager_activity);
if (savedInstance == null) {
PagerFragment frag = PagerFragment.newInstance(buildPagerData());
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().add(R.id.layout_fragments, frag, PAGER_TAG).commit();
}
findViewById(R.id.btnFragments).setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
changeFragmentVisibility();
}
});
}

private List<String> buildPagerData() {
ArrayList<String> pagerData = new ArrayList<String>();
pagerData.add("Robert de Niro");
pagerData.add("John Smith");
pagerData.add("Valerie Irons");
pagerData.add("Metallica");
pagerData.add("Rammstein");
pagerData.add("Zinedine Zidane");
pagerData.add("Ronaldo da Lima");
return pagerData;
}

protected void changeFragmentVisibility() {
Fragment frag = getSupportFragmentManager().findFragmentByTag(PAGER_TAG);
if (frag == null) {
Toast.makeText(this, "No PAGER fragment found", Toast.LENGTH_SHORT).show();
return;
}
boolean visible = frag.isVisible();
Log.d("APSampler", "Pager fragment visibility: " + visible);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (visible) {
ft.hide(frag);
} else {
ft.show(frag);
}
ft.commit();
getSupportFragmentManager().executePendingTransactions();
}
}

its layout file pager_activity.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="4dp" >

<Button
android:id="@+id/btnFragments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Hide/Show fragments" />

<RelativeLayout
android:id="@+id/layout_fragments"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btnFragments"
android:layout_marginBottom="4dp" >
</RelativeLayout>

</RelativeLayout>

Observe that I am adding the PagerFragment when the activity is first shown - and the PagerFragment class:

public class PagerFragment extends Fragment {

private static final String DATA_ARGS_KEY = "PagerFragment.DATA_ARGS_KEY";

private List<String> data;

private ViewPager pagerData;

public static PagerFragment newInstance(List<String> data) {
PagerFragment pagerFragment = new PagerFragment();
Bundle args = new Bundle();
ArrayList<String> argsValue = new ArrayList<String>(data);
args.putStringArrayList(DATA_ARGS_KEY, argsValue);
pagerFragment.setArguments(args);
return pagerFragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
data = getArguments().getStringArrayList(DATA_ARGS_KEY);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.pager_fragment, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
pagerData = (ViewPager) view.findViewById(R.id.pager_data);
setupPagerData();
}

private void setupPagerData() {
PagerAdapter adapter = new LocalPagerAdapter(getChildFragmentManager(), data);
pagerData.setAdapter(adapter);
}

}

its layout (only the ViewPager that takes full size):

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager_data"
android:layout_width="match_parent"
android:layout_height="match_parent" />

and its adapter:

public class LocalPagerAdapter extends FragmentStatePagerAdapter {
private List<String> pagerData;

public LocalPagerAdapter(FragmentManager fm, List<String> pagerData) {
super(fm);
this.pagerData = pagerData;
}

@Override
public Fragment getItem(int position) {
return DataFragment.newInstance(pagerData.get(position));
}

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

This adapter creates a DataFragment for each page:

public class DataFragment extends Fragment {
private static final String DATA_ARG_KEY = "DataFragment.DATA_ARG_KEY";

private String localData;

public static DataFragment newInstance(String data) {
DataFragment df = new DataFragment();
Bundle args = new Bundle();
args.putString(DATA_ARG_KEY, data);
df.setArguments(args);
return df;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
localData = getArguments().getString(DATA_ARG_KEY);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.data_fragment, container, false);
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
view.findViewById(R.id.btn_page_action).setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
Toast.makeText(getActivity(), localData, Toast.LENGTH_SHORT).show();
}
});
((TextView) view.findViewById(R.id.txt_label)).setText(localData);
}
}

and DataFragment's layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="4dp" >

<Button
android:id="@+id/btn_page_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Interogate" />

<TextView
android:id="@+id/txt_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

Enjoy coding!

How to determine when Fragment becomes visible in ViewPager

How to determine when Fragment becomes visible in ViewPager

You can do the following by overriding setUserVisibleHint in your Fragment:

public class MyFragment extends Fragment {
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
}
else {
}
}
}


Related Topics



Leave a reply



Submit