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
Is There a Faster Way to Decode HTML Characters to a String Than HTML.Fromhtml()
How to Add Padding Between Menu Items in Android
How to Perform Minification and Obfuscation with the Jack Compiler
How to Create an Android Activity and Service That Use Separate Processes
Android Imageview Change Tint to Simulate Button Click
Using Asynctask to Speed Up Android App Launch Time
Data Sharing Between Fragments and Activity in Android
Display the App Icon If the Contact Is Associated with the Application in Phone Address Book
Retrofit 2 with Only Form-Data
How to Have a Masked Numeric Input Field
How to Get Screen Display Metrics in Application Class
Onitemclicklistener Was Not Work with the Checkbox
Error Inflating Class Android.Support.V4.View.Viewpager
How to Close Activity and Go Back to Previous Activity in Android