2013-07-13 15 views
17

Uso un FragmentPagerAdapter contenente numerosi frammenti che devono essere avvisati delle modifiche al database. Lo faccio iterando sui frammenti, che implementano un'interfaccia di callback e chiamando un metodo refreshData().FragmentPagerAdapter - Come gestire le modifiche di orientamento?

Questo funziona perfettamente finché il dispositivo non cambia orientamento. Dopo una modifica dell'orientamento, l'interfaccia utente del frammento non si aggiorna visibilmente anche se la chiamata al metodo sembra funzionare.

Da quanto ho letto finora ciò si verifica perché FragmentPagerAdapter gestisce il ciclo di vita dei frammenti ei frammenti che ricevono la richiamata non sono quelli effettivamente visualizzati.

private class DataPagerAdapter extends FragmentPagerAdapter { 

    private DataFragment[] fragments = new DataFragment[] { 
            new FooDataFragment(), BarDataFragment()}; 

    public DataPagerAdapter(android.support.v4.app.FragmentManager fm) { 
     super(fm); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     return fragments[position]; 
    } 

    @Override 
    public int getCount() { 
     return fragments.length; 
    } 

    public DataFragment[] getFragments() { 
     return fragments; 
    } 
} 

protected void refreshData() { 
    for (DataFragment dataFragment : mPagerAdapter.getFragments()) { 
    dataFragment.refreshData(); 
} 

ho temporaneamente risolto questo problema utilizzando un ricevitore di trasmissione all'interno di ciascun frammento, ma questa soluzione sembra essere uno spreco e potrebbe generare perdite di memoria. Come posso risolvere questo correttamente? Uso un layout e una logica diversi in modalità orizzontale, quindi desidero utilizzare i frammenti appena creati dopo un cambio di orientamento.

+1

aggiungere questo al ur tag activty in Android Manifest: configChanges = "orientamento | Screensize | keyboardHidden" (Target API 13+) – TheFlash

+0

minSdkVersion è 7 quindi questo non funzionerà per me –

risposta

52

Sì, come hai detto FragmentManager gestisce i frammenti dopo aver cambiato l'orientamento in modo da non chiamare getItem nell'adattatore. Ma è possibile sovrascrivere il metodo instantiateItem() che viene chiamato anche dopo la modifica dell'orientamento e il cast dell'oggetto Framment e salvarlo nell'array.

@Override 
public Object instantiateItem(ViewGroup container, int position) { 
    DataFragment fragment = (DataFragment) super.instantiateItem(container, position); 
    fragments[position] = fragment; 
    return fragment; 
} 
+0

Questo sembra pulito, purtroppo il comportamento è ancora loro stessi. Ho anche provato ad aggiungere android: configChanges = "orientation" al manifest. –

+1

Io davvero non ti consiglio di usare orientantionChanges in manifest. Quindi stai dicendo che refreshData() è ancora chiamato su vecchi frammenti? Quando chiami refreshData()? Dovresti controllare se instantiateItem() è realmente chiamato e chiamato prima del metodo refreshData(). – koso

+0

Hai ragione, non viene chiamato. Dispari. Eventuali suggerimenti? refreshData() viene chiamato molto tempo dopo l'istanza del frammento, ad esempio quando l'utente preme un pulsante ma può anche essere attivato in modo asincrono da un servizio in background. –

-1

ho avuto problema simile la mia soluzione di lavoro: In attività in cui è un adattatore chiamata di metodo adapter.notifyDataSetChanged();

esclusione getItemPostion() l'adattatore

@Override 
    public int getItemPosition(Object object) { 
     MyFragment frag = (MyFragment)object; 
     frag.refresh(); 
     return POSITION_UNCHANGED; 
    } 

mia FragmentStatePagerAdapater (il mio adattatore) contiene solo un tipo di frammento, ma penso, che potresti usare instanceof (per più tipi di Frammenti) e quindi usare cast o ogni frammento implementerà l'interfaccia con il metodo refresh()

Quindi aggiungere il metodo refresh() nel frammento (s) e utilizzare questa implementazione:

public void refresh() { 
     LayoutInflater inflater = LayoutInflater.from(getActivity()); 
     ViewGroup viewGroup = (ViewGroup) getView(); 
     viewGroup.removeAllViewsInLayout(); 
     View view = onCreateView(inflater, viewGroup, null); 
     viewGroup.addView(view); 

    } 

Questo ha funzionato per me. Il mio parere: Il problema è arrivato, quando il dispositivo cambia orientamento, l'adattatore viene distrutto, ma i frammenti sono ancora in memoria e il sistema tenta di riutilizzarli dopo il cambio di orientamento, ma anche le viste contenute nei frammenti vengono distrutte e i frammenti devono essere "ricreati" (chiamare il metodo onCreateView). Forse ho torto, quindi per favore correggimi ...

(Ci scusiamo per il mio inglese)

+0

Questa soluzione non andrà bene nella maggior parte delle applicazioni. Ci sono casi in cui Android riattiva il tuo frammento per tuo conto come ottimizzazione (ad esempio dopo il cambio di orientamento). Ciò non produrrà sempre i risultati desiderati, ad esempio, se aggiungi il tuo ViewPager al di fuori della funzione onCreate, il frammento otterrà un contenitore Null. Per risolvere questi problemi, puoi rimuovere il frammento in onCreateView() {if (container == null) {removeMeFromFragmentManager(); return null; ...}. Il tuo nuovo FragmentPageAdapter ora ricreare questa istanza di frammento. – dzlatkov

Problemi correlati