android android-fragments android-viewpager android-support-library

android - ViewPager en el Fragmento pierde su contenido cuando se vuelve a mostrar el Fragmento



android-fragments android-viewpager (1)

Tengo un fragmento simple con un ViewPager.

Estoy usando la biblioteca de soporte actualizada, v4 rev18!

Si lo muestro por primera vez, todo funciona bien, si vuelvo y lo muestro de nuevo, la aplicación falla con la siguiente excepción:

java.lang.NullPointerException at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:569) at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211) at android.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1281) at android.view.View.dispatchRestoreInstanceState(View.java:12043) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2688) at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2694) at android.view.View.restoreHierarchyState(View.java:12021) at android.support.v4.app.Fragment.restoreViewState(Fragment.java:425) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:949) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440) at android.os.Handler.handleCallback(Handler.java:615) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4800) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:565) at dalvik.system.NativeStart.main(Native Method)

Mi clase simple parece seguir y debería estar, en realidad, bien ...

public class RoutineDayFragment extends BaseFragment { private RoutinesActivity mParent = null; @InjectView(R.id.pager) MyViewPager pager = null; @InjectView(R.id.indicator) PagerSlidingTabStrip indicator = null; private FragmentStatePagerAdapter mAdapter = null; @Override public void onAttach(Activity activity) { super.onAttach(activity); mParent = ((RoutinesActivity) getBaseActivity()); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.view_pager, container, false); Views.inject(this, v); mAdapter = new FragmentStatePagerAdapter(getChildFragmentManager()) { @Override public int getCount() { if (mParent.getSharedData().selectedRoutine == -1) return 0; return mParent.getSharedData().routines.get(mParent.getSharedData().selectedRoutine).getRWorkoutDay().size(); } @Override public Fragment getItem(int pos) { return DayFragment.newInstance(pos); } @Override public CharSequence getPageTitle(int pos) { return Common.getString(R.string.day) + (pos + 1); } }; pager.setAdapter(mAdapter); indicator.setViewPager(pager); return v; } }


Use una AsyncTask para establecer el ViewPagerAdapter:

private class SetAdapterTask extends AsyncTask<Void, Void, Void> { protected Void doInBackground(Void... params) { return null; } @Override protected void onPostExecute(Void result) { if(mAdapter != null) mViewPager.setAdapter(mAdapter); } }

Llámalo así:

mAdapter = new PageAdapter(getChildFragmentManager()); new SetAdapterTask().execute();

Y reinicie el adaptador en el método onResume( ) de su Fragmento.

ACTUALIZACIÓN - ¿Cómo anidar un ViewPager dentro de un fragmento?

Muy bien, aquí está. Modifiqué el ejemplo de Google de la navegación efectiva para que se ajuste a sus inquietudes.

¿Qué he creado?

  • Creé una aplicación simple, que contiene un MainActivity con un ViewPager y 3 pestañas.
  • Cada una de estas pestañas está representada por un fragmento que también contiene un ViewPager.
  • El ViewPager dentro del Fragmento contiene 10 páginas.
  • Así que tenemos 3 pestañas / fragmentos "principales", cada uno con 10 fragmentos más.
  • Para fines de demostración, hice que el ViewPager de nivel superior no fuera deslizable , así que tienes que usar las pestañas para cambiar entre los Fragmentos principales (creé un CustomViewPager e hice algunos cambios para eliminar la capacidad de deslizamiento de ViewPagers)
  • El ViewPager dentro de los Fragmentos principales se puede deslizar, así que puedes deslizar para cambiar entre los sub-Fragmentos, y presionar las pestañas para cambiar entre los Fragmentos principales
  • Si hace clic en un subgrupo, se inicia una nueva actividad.
  • Si regresa a la actividad anterior cuando se cierra la nueva actividad, se conserva el estado de Fragmentos y ViewPager.
  • Al cambiar los fragmentos principales, su estado también se conserva

Aquí está la actividad principal. Java

Contiene dos adaptadores, uno para los Fragmentos principales, uno para los Sub Fragmentos. Además, hay dos clases de Fragmentos, una es el Fragmento que contiene el ViewPager (el fragmento principal), la otra es el Sub-Fragmento (dentro del ViewPager anidado)

public class MainActivity extends FragmentActivity implements ActionBar.TabListener { AppSectionsPagerAdapter mAppSectionsPagerAdapter; NonSwipeableViewPager mViewPager; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager()); // Set up the action bar. final ActionBar actionBar = getActionBar(); actionBar.setHomeButtonEnabled(false); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // Set up the ViewPager, attaching the adapter and setting up a listener for when the // user swipes between sections. mViewPager = (NonSwipeableViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mAppSectionsPagerAdapter); mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { actionBar.setSelectedNavigationItem(position); } }); // For each of the sections in the app, add a tab to the action bar. for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) { actionBar.addTab( actionBar.newTab() .setText(mAppSectionsPagerAdapter.getPageTitle(i)) .setTabListener(this)); } } @Override public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {} @Override public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) { // When the given tab is selected, switch to the corresponding page in the ViewPager. mViewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {} public static class AppSectionsPagerAdapter extends FragmentPagerAdapter { public AppSectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { switch (i) { default: // The other sections of the app are dummy placeholders. Fragment fragment = new ViewPagerContainerFragment(); return fragment; } } @Override public int getCount() { return 3; } @Override public CharSequence getPageTitle(int position) { return "Tab " + (position +1); } } public static class ViewPagerAdapter extends FragmentPagerAdapter { public ViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { switch (i) { default: // The other sections of the app are dummy placeholders. Fragment fragment = new ViewPagerFragment(); Bundle b = new Bundle(); b.putString("key", "I am fragment nr " + i); fragment.setArguments(b); return fragment; } } @Override public int getCount() { return 10; } } /** * THIS FRAGMENT CONTAINS A VIEWPAGER */ public static class ViewPagerContainerFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.main_fragment, container, false); ViewPager pager = (ViewPager) rootView.findViewById(R.id.nestedViewPager); pager.setAdapter(new ViewPagerAdapter(getChildFragmentManager())); return rootView; } } /** * THIS FRAGMENT IS INSIDE THE VIEWPAGER */ public static class ViewPagerFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.sub_fragment, container, false); ((TextView) rootView.findViewById(R.id.tv1)).setText(getArguments().getString("key")); ((TextView) rootView.findViewById(R.id.tv1)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(getActivity(), CollectionDemoActivity.class); startActivity(intent); } }); return rootView; } } }

activity_main.xml

<com.example.android.effectivenavigation.NonSwipeableViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" />

main_fragment.xml

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/nestedViewPager" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="24sp" />

sub_fragment.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tv1" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="50sp" />

El resultado final se ve así:

Tenemos 3 fragmentos de nivel superior, cada uno de los cuales contiene un ViewPager con 10 fragmentos.