2012-09-03 16 views
8

Tengo un ViewPager (extiende FragmentPagerAdapter) que tiene dos Fragments. Lo que necesito es actualizar un ListView para cada Fragment cuando deslizo entre ellos. Para esto he implementado la interfaz ViewPager.OnPageChangeListener (es decir, onPageScrollStateChanged). Para mantener referencias a Fragment s utilizo un HashTable. Almaceno referencias a Fragments en HashTable en getItem() método:FragmentPagerAdapter no recrea Fragmentos en el cambio de orientación?

@Override 
     public Fragment getItem(int num) { 
      if (num == 0) { 
       Fragment itemsListFragment = new ItemsListFragment(); 
       mPageReferenceMap.put(num, itemsListFragment); 
       return itemsListFragment; 
      } else { 
       Fragment favsListFragment = new ItemsFavsListFragment(); 
       mPageReferenceMap.put(num, favsListFragment); 
       return favsListFragment; 
      } 
     } 

Así que cuando desliza el dedo de uno Fragment a otro del onPageScrollStateChanged desencadena cuando utilizo el HashTable llamar al método requerido tanto en Fragments (actualización):

public void refreshList() { 
     ((ItemsListFragment) mPageReferenceMap.get(0)).refresh(); 
     ((ItemsFavsListFragment) mPageReferenceMap.get(1)).refresh(); 
    } 

Todo va bien hasta que ocurra el evento orientation change. Después de que el código en refresh() método, que es:

public void refresh() { 
     mAdapter.changeCursor(mDbHelper.getAll()); 
     getListView().setItemChecked(-1, true); // The last row from a exception trace finishes here (my class). 
    } 

resultados en IllegalStateException:

java.lang.IllegalStateException: Content view not yet created 
     at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328) 
     at android.support.v4.app.ListFragment.getListView(ListFragment.java:222) 
     at ebeletskiy.gmail.com.passwords.ui.ItemsFavsListFragment.refresh(ItemsFavsListFragment.java:17) 

Suponiendo que la vista Content no se crea de hecho I establecer la variable de boolean en onActivityCreated() método para true y solía if/else condición para llamar al getListView() o no, que muestra la actividad y la vista de contenido creada con éxito.

Luego estaba depurando para ver cuando FragmentPagerAdapter invoca getItem() y sucede que el método no se llama después del evento orientation change. Parece que ViewPager contiene referencias al antiguo Fragments. Esta es solo mi suposición.

Así que, ¿hay alguna manera de hacer cumplir la ViewPager para llamar getItem() de nuevo, por lo que puede utilizar referencias adecuadas a la corriente Fragments? Puede ser alguna otra solución? Muchas gracias.

Respuesta

4

Luego estaba depurando para ver cuándo FragmentPagerAdapter invoca getItem() y sucede que el método no se llama después del evento de cambio de orientación. Parece que ViewPager contiene referencias a Fragmentos antiguos.

Los fragmentos se deben recrear automáticamente, al igual que cualquier fragmento tiene un cambio de configuración. La excepción sería si usó setRetainInstance(true), en cuyo caso deberían ser los mismos objetos de fragmento que antes.

Entonces, ¿hay alguna forma de hacer que ViewPager vuelva a llamar a getItem() para que pueda utilizar las referencias adecuadas a los fragmentos actuales?

¿Qué pasa con los fragmentos que están allí?

+0

No uso 'setRetainInstance()' allí. El problema está en la excepción que aparece después del 'cambio de orientación'. Solo asumo que los Fragmentos viejos están en uso, porque verifiqué la condición de 'onActivityCreated()' para ambos. – Eugene

+0

@siik: ¿Cuándo llamas a este método 'refresh()'? ¿Y cuándo sacas los fragmentos recién creados para poblar tu (ick) 'Hashtable'? – CommonsWare

+0

Llamo a este método 'refresh()' en 'onPageScrollStateChanged()' (que es la implementación de la interfaz 'ViewPager.OnPageChangeListener', es decir, cuando deslizo entre' Fragments'). Y llené 'HashTable' en' getItem() 'método de clase que se extiende' FragmentPagerAdapter' – Eugene

0

he pasado algunos días en busca de una solución para este problema, y ​​muchos puntos fue descubierto la:

  • uso FragmentPagerAdapter en lugar de FragmentStatePagerAdapter

  • uso FragmentStatePagerAdapter en lugar de FragmentPagerAdapter

  • return POSITION_NONE en getItemPosition anulación de FragmentPagerAdapter

  • no utilice FragmentPagerAdapter si necesita cambios dinámicos de fragmentos

  • y muchos muchos muchos otros ...

En mi aplicación, como Eugene, yo he conseguido los casos de creado fragmentos Lo guardo en un HashMap<String,Fragment> dentro de una clase especializada, por lo que los fragmentos nunca se lanzan, acelerando mi aplicación (pero consumiendo más recursos).

El problema fue cuando giré mi tableta (y mi teléfono). El getItem(int) ya no se llamó para ese fragmento, y no pude cambiarlo.

que realmente pasó muchos tiempo hasta que realmente encontrado una solución, así que necesito compartirlo con la comunidad StackOverflow, que me ayuda a tantas muchas veces ...

La solución para este problema, aunque el trabajo duro para encontrarlo, es bastante simple:

Hemos de tener la referencia a FragmentManager en el constructor de FragmentPagerAdapter se extiende:

public class Manager_Pager extends FragmentPagerAdapter { 

    private final FragmentManager mFragmentManager; 
    private final FragmentActivity mContext; 

    public Manager_Pager(FragmentActivity context) { 

     super(context.getSupportFragmentManager()); 

     this.mContext = context; 
     this.mFragmentManager = context.getSupportFragmentManager(); 
    } 

    @Override 
    public int getItemPosition(Object object) { 

// here, check if this fragment is an instance of the 
// ***FragmentClass_of_you_want_be_dynamic*** 

     if (object instanceof FragmentClass_of_you_want_be_dynamic) { 

// if true, remove from ***FragmentManager*** and return ***POSITION_NONE*** 
// to force a call to ***getItem*** 

      mFragmentManager.beginTransaction().remove((Fragment) object).commit(); 
      return POSITION_NONE; 
     } 

     //don't return POSITION_NONE, avoid fragment recreation. 
     return super.getItemPosition(object); 
    } 

    @Override 
    public Fragment getItem(int position) { 


     if (position == MY_DYNAMIC_FRAGMENT_INDEX){ 

      Bundle args = new Bundle(); 
      args.putString("anything", position); 
      args.putString("created_at", ALITEC.Utils.timeToStr()); 

      return Fragment.instantiate(mContext, FragmentClass_of_you_want_be_dynamic.class.getName(), args); 

     }else 

     if (position == OTHER){ 

      //... 

     }else 

     return Fragment.instantiate(mContext, FragmentDefault.class.getName(), null); 

    } 
} 

eso es todo. Y funcionará como un amuleto ...

+1

no funciona para mí getItem no recurrir al cambio de orientación. – JosephM

+0

this.mFragmentManager = context.getSupportFragmentManager(); – alijunior

Cuestiones relacionadas