Insertar y quitar fragmentos en viewpager correctamente

Estoy haciendo una aplicación de adroid con viewpager y fragmentos. Quiero hacer una opción para agregar o quitar páginas de fragmentos al buscapersonas dinámicamente. Tengo un FragmentPagerAdapter personalizado:

public class MyAdapter extends FragmentPagerAdapter implements TitleProvider{ protected final List<PageFragment> fragments; /** * @param fm * @param fragments */ public MyAdapter(FragmentManager fm, List<PageFragment> fragments) { super(fm); this.fragments = fragments; } public void addItem(PageFragment f){ fragments.add(f); notifyDataSetChanged(); } public void addItem(int pos, PageFragment f){ for(int i=0;i<fragments.size();i++){ if(i>=pos){ getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(i))).commit(); } } fragments.add(pos,f); notifyDataSetChanged(); pager.setAdapter(this); pager.setCurrentItem(pos); } public void removeItem(int pos){ getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(pos))).commit(); for(int i=0;i<fragments.size();i++){ if(i>pos){ getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentByTag(getFragmentTag(i))).commit(); } } fragments.remove(pos); notifyDataSetChanged(); pager.setAdapter(this); if(pos<fragments.size()){ pager.setCurrentItem(pos); }else{ pager.setCurrentItem(pos-1); } } @Override public Fragment getItem(int position) { return fragments.get(position).toFragment(); } @Override public int getCount() { return fragments.size(); } @Override public int getItemPosition(Object object) { return POSITION_NONE; } private String getFragmentTag(int pos){ return "android:switcher:"+R.id.pager+":"+pos; } public String getTitle(int position) { String name = fragments.get(position).getName(); if(name.equals("")) return "- "+position+" -"; return name; } } 

Puedo quitar cualquier fragmento excepto el 0. cuando intento quitarlo Conseguí un NullPointerException en el notifyDataSetChanged (); O en el pager.setAdapter (este); Si comento la notificación.

También obtuve una NullPointerException cuando intento insertar una nueva página. Cuando agrego la nueva página al final de la lista está trabajando muy bien. Incluso traté de readd los fragmentos en el inserto con esto después de los fragmentos.add (pos, f)

  for(int i=0;i<fragments.size();i++){ if(i>=pos){ getSupportFragmentManager().beginTransaction().add(fragments.get(i).toFragment(),getFragmentTag(i-1)).commit(); } } 

Si utilizo getFragmentTag(i-1) tengo nullpointer de nuevo. Con el uso de i sólo obtuve illegalstateexception porque no se puede modificar la etiqueta del fragmento. Con beginTransaction().add(pager.getId,fragments.get(i).toFragment()) sigue siendo nullpointer …

Mi pregunta es: ¿qué estoy haciendo mal, y cómo se puede hacer correctamente? (Y tal vez: de donde notyfyDataSetChanged() obtener los datos cuando las causas nullpointerexception?)

Esto es lo que he utilizado para resolver el problema con fragmentos que se etiquetan cuando instanciado y el hecho de que los fragmentos marcados anteriormente no pueden cambiar de posición dentro de ViewPager al intentar agregar o quitar páginas, es decir, obtener la excepción:

Java.lang.IllegalStateException: No se puede cambiar la etiqueta del fragmento MyFragment {4055f558 id = 0x7f050034 android: switcher: 2131034164: 3}: android: switcher: 2131034164: 3 ahora android: switcher: 2131034164: 4

Este adaptador se crea con una lista de todas las páginas por adelantado y puede utilizar setEnabled (int position, boolean enabled) para deshabilitar o activar ciertas páginas que ocultan o muestran estas páginas en ViewPager.

Funciona manteniendo una lista interna de todos los fragmentos pero exponiéndose al ViewPager y asignando las posiciones de los fragmentos habilitados solamente.

 public class DynamicFragmentPagerAdapter extends FragmentPagerAdapter { public final ArrayList<Fragment> screens = new ArrayList<Fragment>(); private Context context; private List<AtomicBoolean> flags = new ArrayList<AtomicBoolean>(); public DynamicFragmentPagerAdapter(FragmentManager fm, Context context, List<Class<?>> screens) { super(fm); this.context = context; for(Class<?> screen : screens) addScreen(screen, null); notifyDataSetChanged(); } public DynamicFragmentPagerAdapter(FragmentManager fm, Context context, Map<Class<?>, Bundle> screens) { super(fm); this.context = context; for(Class<?> screen : screens.keySet()) addScreen(screen, screens.get(screen)); notifyDataSetChanged(); } private void addScreen(Class<?> clazz, Bundle args) { screens.add(Fragment.instantiate(context, clazz.getName(), args)); flags.add(new AtomicBoolean(true)); } public boolean isEnabled(int position) { return flags.get(position).get(); } public void setEnabled(int position, boolean enabled) { AtomicBoolean flag = flags.get(position); if(flag.get() != enabled) { flag.set(enabled); notifyDataSetChanged(); } } @Override public int getCount() { int n = 0; for(AtomicBoolean flag : flags) { if(flag.get()) n++; } return n; } @Override public Fragment getItem(int position) { return screens.get(position); } @Override public int getItemPosition(Object object) { return POSITION_NONE; // To make notifyDataSetChanged() do something } @Override public void notifyDataSetChanged() { try { super.notifyDataSetChanged(); } catch (Exception e) { Log.w("", e); } } private List<Fragment> getEnabledScreens() { List<Fragment> res = new ArrayList<Fragment>(); for(int n = 0; n < screens.size(); n++) { if(flags.get(n).get()) res.add(screens.get(n)); } return res; } @Override public Object instantiateItem(ViewGroup container, int position) { // We map the requested position to the position as per our screens array list Fragment fragment = getEnabledScreens().get(position); int internalPosition = screens.indexOf(fragment); return super.instantiateItem(container, internalPosition); } @Override public CharSequence getPageTitle(int position) { Fragment fragment = getEnabledScreens().get(position); if(fragment instanceof TitledFragment) return ((TitledFragment)fragment).getTitle(context); return super.getPageTitle(position); } public static interface TitledFragment { public String getTitle(Context context); } } 

Tengo una solución que funciona con un adaptador no basado en fragmentos. Echa un vistazo a mi mensaje y ver si ayuda.

Puedo quitar cualquier fragmento excepto el 0.

Para mi funciona si solo usas una condición> = whitin en el loop forIl de removeItem:

  if (i >= pos){ fm.beginTransaction().remove(fragments.get(i).getFragment()).commit(); } 
  • Fragmento de actualización de ViewPager en el dispositivo
  • Cargar imagen desde la cámara a ImageView en un fragmento
  • Error "java.lang.IllegalStateException: No se puede cambiar la etiqueta de fragmento" cuando se utiliza ViewPager # setCurrentItem ()
  • ¿Por qué FragmentManager getBackStackEntryCount () devuelve cero?
  • MapView en Fragmento (Android 4.0 o superior)
  • Servicio de Android> Actividad> Fragmento con ViewPager
  • Inicialización del reproductor de YouTube en Fragmento
  • Extender FragmentActivity en lugar de Activity
  • Fragmento dentro de ViewPager devolver null en getView ()
  • ADT de Android: no fragment_main.xml, sólo activity_main.xml
  • Android - No se puede usar popup en Fragmento
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.