Fragmento con ViewPager dentro de Fragmento y FragmentStatePagerAdapter resultados en Excepción (con ejemplo completo)

Tengo un Fragmento simple con un ViewPager.

Estoy usando la biblioteca de soporte actualizada, v4 rev18!

Si muestro el sub-fragmento la primera vez, todo funciona bien, si vuelvo a mostrarlo de nuevo, la aplicación se bloquea con la siguiente excepción:

Tengo un ejemplo completo que demuestra, CUANDO está ocurriendo la excepción siguiente:

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) 

Puedo usar el ViewPager en un fragmento del niño en cada otra manera, pero no puedo conseguirla que trabaja si agrego / quito los sub fragmentos manualmente y uso FragmentStatePagerAdapter en los fragmentos secundarios …

El siguiente ejemplo debería funcionar, pero no … ya he añadido algún código que soluciona algunos problemas, pero no resuelve todos los problemas …

 import java.lang.reflect.Field; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.app.FragmentTransaction; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.TextView; public class TestActivity extends FragmentActivity implements OnClickListener { private Fragment fragment1; private Fragment fragment2; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test_main); fragment1 = getSupportFragmentManager().findFragmentByTag("fragment1"); fragment2 = getSupportFragmentManager().findFragmentByTag("fragment2"); } @Override public void onClick(View v) { Fragment nextFragment = null; String nextFragmentTag = null; if (v.getId() == R.id.button1) { if (fragment1 == null) fragment1 = ContainerFragment.newInstance(1); nextFragment = fragment1; nextFragmentTag = "fragment1"; } else if (v.getId() == R.id.button2) { if (fragment2 == null) fragment2 = ContainerFragment.newInstance(2); nextFragment = fragment2; nextFragmentTag = "fragment2"; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.main, nextFragment, nextFragmentTag); transaction.addToBackStack(null); transaction.commit(); } public static class MainPagerAdapter extends FragmentStatePagerAdapter { public int button; public MainPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { return SubFragment.newInstance(button, i); } @Override public int getCount() { return 10; } } public static class ContainerFragment extends Fragment { static ContainerFragment newInstance(int pos) { ContainerFragment f = new ContainerFragment(); Bundle args = new Bundle(); args.putInt("pos", pos); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.view_pager, container, false); ViewPager pager = (ViewPager) rootView.findViewById(R.id.pager); MainPagerAdapter adapter = new MainPagerAdapter(getChildFragmentManager()); adapter.button = getArguments().getInt("pos"); pager.setAdapter(adapter); return rootView; } // --------------------------------------------------------------- // HACK FIX für java.lang.IllegalStateException: No activity // --------------------------------------------------------------- private static final Field sChildFragmentManagerField; static { Field f = null; try { f = android.support.v4.app.Fragment.class.getDeclaredField("mChildFragmentManager"); f.setAccessible(true); } catch (NoSuchFieldException e) { } sChildFragmentManagerField = f; } @Override public void onDetach() { super.onDetach(); if (sChildFragmentManagerField != null) { try { sChildFragmentManagerField.set(this, null); } catch (Exception e) { } } } } public static class SubFragment extends Fragment { static SubFragment newInstance(int button, int pos) { SubFragment f = new SubFragment(); Bundle args = new Bundle(); args.putString("key", "Button " + button + "Fragment " + pos); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.test_subfragment, container, false); ((TextView) rootView.findViewById(R.id.tv1)).setText(getArguments().getString("key")); return rootView; } } } 

En aras de la integridad, agrego los archivos xml también:

Test_main.xml

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button1" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button2" /> </LinearLayout> </FrameLayout> 

Test_subfragment.xml

 <?xml version="1.0" encoding="utf-8"?> <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" /> 

View_pager.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/llContainer" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> 

Agregue un FrameLayout adicional a su diseño de la actividad principal. Aquí es donde pusiste el Fragmento.

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button1" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="Button2" /> <!-- add this --> <FrameLayout android:id="@+id/fragment_frame" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout> </LinearLayout> </FrameLayout> 

Puesto que usted está agregando sus fragmentos al BackStack , no hay necesidad de guardar una instancia de ellos. Esta es la razón por la que se bloquea la aplicación. Ajuste su método onClick() siguiente manera:

  @Override public void onClick(View v) { Fragment nextFragment = null; String nextFragmentTag = null; if (v.getId() == R.id.button1) { nextFragment = ContainerFragment.newInstance(1); nextFragmentTag = "fragment1"; } else if (v.getId() == R.id.button2) { nextFragment = ContainerFragment.newInstance(2); nextFragmentTag = "fragment2"; } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.fragment_frame, nextFragment, nextFragmentTag); transaction.addToBackStack(null); transaction.commit(); } 

He probado el código. Cambiar los fragmentos con los botones funciona, y el estado que el ViewPager se dejó cuando se retuerce a él se conserva .

  • FragmentManager reemplazar fragmentos sin llamar onPause () onDestroy () para el fragmento antiguo
  • GetBackStackEntryCount () siempre devuelve 0 incluso después de agregar addToBackStack y executePendingTransactions ()
  • Guardar y restaurar el estado de la interfaz de usuario del fragmento cuando se empuja y sale del backstack
  • Android.support.v4.app.FragmentManager O ¿android.app.FragmentManager?
  • Aplicar fuerza cerrar en viewPager.setAdapter (adaptador)
  • GetSupportFragmentManager no compila en DialogFragment
  • Se hace clic en un diseño invisible detrás del fragmento:
  • Asyncronious FragmentManager commit
  • Cómo establecer una etiqueta en un fragmento en Android
  • Sustitución de fragmentos en una actividad que no llama aAttach, onCreate, onCreateView, etc.
  • Guardar estado de fragmentos en backstack
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.