2012-09-03 26 views
8

Ho un ViewPager (si estende FragmentPagerAdapter) che contiene due Fragments. Quello di cui ho bisogno è di aggiornare un ListView per ogni Fragment quando faccio scorrere tra di loro. Per questo ho implementato l'interfaccia ViewPager.OnPageChangeListener (ovvero onPageScrollStateChanged). Per conservare i riferimenti a Fragment s uso un HashTable. I memorizzare i riferimenti a Fragments in HashTable in getItem() metodo:FragmentPagerAdapter non ricrea frammenti sul cambio di orientamento?

@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; 
      } 
     } 

Così, quando ho scorrere da un Fragment a un altro il onPageScrollStateChanged innesca in cui uso il HashTable di chiamare il metodo richiesto sia Fragments (refresh):

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

Tutto va bene fino all'evento orientation change. Dopo che il codice refresh() metodo, che è:

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

risultati in 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) 

Assumendo la vista Content non viene creata infatti a impostare la variabile boolean in onActivityCreated() metodo per true e usato if/else condizione di chiamare getListView() o meno, che ha mostrato la visualizzazione di attività e contenuto creata correttamente.

Quindi eseguivo il debug per vedere quando FragmentPagerAdapter invoca getItem() e succede che il metodo non viene chiamato dopo l'evento orientation change. Quindi sembra che ViewPager detenga i riferimenti al vecchio Fragments. Questa è solo la mia ipotesi.

Quindi, c'è un modo per far rispettare il ViewPager per chiamare di nuovo getItem(), in modo che io possa utilizzare i riferimenti corretti allo Fragments corrente? Potrebbe essere un'altra soluzione? Grazie mille.

risposta

4

Quindi eseguivo il debug per vedere quando FragmentPagerAdapter richiama getItem() e succede che il metodo non viene chiamato dopo l'evento di modifica dell'orientamento. Quindi sembra che ViewPager abbia dei riferimenti ai vecchi Frammenti.

I frammenti devono essere ricreati automaticamente, proprio come qualsiasi frammento si trova in una modifica di configurazione. L'eccezione sarebbe se si fosse utilizzato setRetainInstance(true), nel qual caso dovrebbero essere gli stessi oggetti frammento di prima.

Quindi, c'è un modo per far sì che ViewPager richiami di nuovo getItem(), così posso usare i riferimenti corretti agli attuali Frammenti?

Cosa c'è di sbagliato con i frammenti che ci sono?

+0

Non uso 'setRetainInstance()'. Il problema è nell'eccezione che si apre dopo "cambio di orientamento". Suppongo che i vecchi Frammenti siano in uso, perché ho controllato la condizione che 'onActivityCreated() 'sia eseguito per entrambi. – Eugene

+0

@siik: Quando chiamate questo metodo 'refresh()'? E quando tiri fuori i frammenti appena creati per popolare il tuo (ick) 'Hashtable'? – CommonsWare

+0

Sto chiamando questo metodo 'refresh()' in 'onPageScrollStateChanged()' (che è l'implementazione dell'interfaccia 'ViewPager.OnPageChangeListener', cioè quando passo il dito su' Fragments'). E popolo 'HashTable' nel metodo di classe' getItem() 'che estende' FragmentPagerAdapter' – Eugene

0

Ho passato alcuni giorni alla ricerca di una soluzione per questo problema, e molti punti si è capito:

  • uso FragmentPagerAdapter invece di FragmentStatePagerAdapter

  • uso FragmentStatePagerAdapter invece di FragmentPagerAdapter

  • ritorno POSITION_NONE su getItemPosition override di FragmentPagerAdapter

  • non utilizzare FragmentPagerAdapter se avete bisogno di cambiamenti dinamici di frammenti

  • e molti molti molti altri ...

Nella mia app, come Eugene, io stesso gestito le istanze del creato frammenti. Lo tengo in uno HashMap<String,Fragment> all'interno di una classe specializzata, quindi i frammenti non vengono mai rilasciati, velocizzando la mia app (ma consumando più risorse).

Il problema è stato quando ruoto il mio tablet (e il mio telefono). Lo getItem(int) non è stato più chiamato per quel frammento e non potevo cambiarlo.

ho davvero trascorso molti tempo fino a quando davvero trovato una soluzione, quindi ho bisogno di condividerlo con StackOverflow comunità, che mi aiuta tante tante volte ...

La soluzione per questo problema, anche se il duro lavoro a trovarlo, è abbastanza semplice:

Basta tenere il riferimento alla FragmentManager nel costruttore di FragmentPagerAdapter estende:

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); 

    } 
} 

Questo è tutto. E funzionerà come un fascino ...

+1

non ha funzionato per me getItem non chiama mai il cambio di orientamento. – JosephM

+0

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

Problemi correlati