Il frammento in ViewPager utilizzando FragmentPagerAdapter è vuoto la seconda volta che viene visualizzato


98

Ho un'interfaccia dei frammenti con schede lungo la parte inferiore che aprono diversi frammenti nella vista principale.

Ho un frammento particolare che è un elenco di elementi. Se l'utente seleziona uno degli elementi in questo elenco, si apre un altro frammento che contiene un viewpager che scorre orizzontalmente tra tutti gli elementi nell'elenco nel frammento precedente. Funziona alla grande.

Il viewpager usa un FragmentPagerAdapter per visualizzare gli elementi.

Il problema si verifica quando l'utente seleziona un elemento nell'elenco, lo visualizza, quindi preme il pulsante sulla barra delle schede per tornare all'elenco, quindi seleziona un altro elemento. La seconda volta che viene selezionato un elemento, al posto del viewpager appare una schermata vuota. Quando ciò accade, non ricevo errori nel mio LogCat.

Perché il viewpager appare solo la prima volta?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        if (mCursor == null) return 0;
        else return mCursor.getCount();
    }

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}

Risposte:


221

Ho avuto lo stesso problema. Cambiando la classe genitore del mio PageAdapter da android.support.v4.app.FragmentPagerAdapterper android.support.v4.app.FragmentStatePagerAdapterrisolvere il mio ViewPagerproblema di visualizzazione sulla "seconda volta"!


2
Non sto scherzando? Non ho più questo codice altrimenti lo testerei. Forse questa risposta aiuterà qualcun altro.
howettl

10
Che uomo! Sono stati giorni alla ricerca di questa soluzione! Grazie mille, funziona alla grande. Ma lo sviluppatore che è in me si chiede quale impatto ha quel cambiamento? Voglio dire, perché non ha funzionato prima e perché in StatePagerAdapter
Anand Sainath

1
inoltre è necessario @Override public int getItemPosition (Object object) {return POSITION_NONE; }
Helin Wang

1
Ha funzionato anche per me. Ecco un collegamento. Sembra salvare lo stato del frammento, il che fa la differenza. developer.android.com/reference/android/support/v4/app/…
Tjaart

1
È una coincidenza che funzioni, la risposta giusta è quella di @Daniel F. Ad ogni modo, per comodità dei commentatori qui, la differenza tra FragmentPagerAdaptere FragmentStatePagerAdapterè nel primo che è più adatta per poche pagine, conserva tutti i frammenti in memoria quindi avendo le migliori prestazioni al cambio di pagina, mentre la seconda è più adatta per molte pagine pagine, distrugge i frammenti, mantenendo solo il loro stato, è più efficiente in termini di memoria ma un po 'più lento nel cambio di pagina.
Cristina De Rito

87

Sono riuscito a risolverlo sostituendo getFragmentManager()con getChildFragmentManager()nel frammento genitore. Questo frammento padre stava istanziando un android.support.v4.app.FragmentPagerAdapter per contenere frammenti paginabili (scorrevoli), che richiede un gestore di frammenti nel costruttore. A questo costruttore ho passato il valore di ritorno di getChildFragmentManager().

il collegamento di hackbod era fondamentale ( https://developer.android.com/about/versions/android-4.2.html#NestedFragments ), che è stato trovato in questo post Fragments within Fragments

Per annidare un frammento, è sufficiente chiamare getChildFragmentManager()il frammento in cui si desidera aggiungere un frammento. Ciò restituisce un FragmentManager che puoi usare come faresti normalmente dall'attività di primo livello per creare transazioni di frammenti.


Grazie ... stavo riscontrando un problema simile cercando di reistituire una visualizzazione a schede scorrevoli dopo onresume () che conteneva un fragmentpageradapter ... il tutorial che ho usato era del 2016 e dovevo ancora cambiarlo in fragmentstatepageradapter per ottenerlo lavoro. vorrei sapere perché.
Nerdy Bunz

questa risposta mi ha fatto risparmiare molto tempo. Perché solo l'uso FragmentStatePagerAdapternon risolve la domanda qui posta. insieme al FragmentStatePagerAdapterframmento genitore YourAdapter adapter = new YourAdapter (getChildFragmentManager()); deve essere aggiunto
MMK

17

per me ho dovuto chiamare questo sul mio viewpager:

myViewPager.setSaveFromParentEnabled(false);

Ho avuto il problema in cui il viewpager non si aggiornava e tutto ciò che ho visto era uno schermo bianco vuoto dove dovrebbero essere i frammenti. Stavo passando getChildFragmentManager ma non ha aiutato.


1
Perché nel mondo ha funzionato? Questo ha risolto il mio problema ma non ho idea del perché.
ClayHerendeen

Ora l'ho rimosso dal mio codice. Il gestore dei frammenti stava causando il problema. Prova a passare da getchildfragmentmanager a getfragmentmanager
j2emanue

L'ho già provato. Ho schede nidificate ciascuna con ViewPagers che hanno disabilitato lo scorrimento. So che questo è un design scadente ma i desideri dei clienti non sono miei. Sto usando un childFragmentManager per la barra delle schede di livello superiore. La commutazione per la tabbar / viewpager di livello inferiore non sembra risolvere il problema. Suppongo che per ora rimarrò con setSaveFromParentEnabled (false) poiché funziona.
ClayHerendeen

Stai utilizzando l'ultima libreria di supporto
j2emanue

2
Stavo affrontando lo stesso problema negli ultimi 2 giorni .. La tua soluzione ha funzionato per me. Grazie !
brijexecon

11

Nel mio caso molto particolare, in cui stavo utilizzando un CoordinatorLayout con un AppBarLayout e ViewPager, ciò che ha risolto per me è stata la rimozione di android: fitsSystemWindows = "true" dalle mie proprietà xml di AppBarLayout .

Non chiedermi perché. So che suona un po 'ridicolo e come se non avesse alcuna correlazione, ma era questa singola riga l'unica cosa che stava causando problemi poiché stavo già usando getChildFragmentManager () nel mio adattatore. Ho passato un'intera giornata a eseguire il debug del mio codice solo per trovarlo, quindi spero che faccia risparmiare tempo a qualcun altro.


3
Oh amico ... stavo quasi per arrendermi con questo problema. Hai reso la mia dannata giornata! Geez Google, WTF è sbagliato con AppBarLayout? Ho guardato quasi cento pagine e ho passato un sacco di ore a eseguire il debug cercando di risolvere questo problema senza fortuna. Sono davvero grato di essere finalmente riuscito a risolvere il problema con il tuo commento. Molte grazie! PS: Ero così disperato che ho persino creato un problema nell'AOSP: code.google.com/p/android/issues/… XD
Guillem Roca

Grazie per il suggerimento. Almeno ci ha aiutato a risolvere il problema. Ora stiamo cercando di scoprire l'opzione per renderlo a schermo intero
Paresh Mayani

Sei un salvavita! Ero assolutamente all'oscuro del motivo per cui avevo questo problema e ancora all'oscuro del perché funzionasse!
nandu

10

Ho avuto lo stesso problema per il quale ho cambiato l'adattatore da FragmentPagerAdaptera FragmentStatePagerAdaptere getFragmentManager()nel frammento genitore agetChildFragmentManager()

Il motivo alla base di ciò è FragmentStatePagerAdapterutile per memorizzare un numero elevato di pagine e la memoria associata a ciascuna pagina visitata è inferiore in quanto mantiene solo lo stato salvato del frammento mentre la pagina non è visibile. Ciò riduce l'overhead durante il passaggio tra i frammenti.


4

Prova a mettere setOffscreenPageLimit (int limit)su genitore ViewPager.

mViewPager.setOffscreenPageLimit(totalPages-1);

Questo ha funzionato per me come un fascino.

Nel mio caso avevo frammento all'interno TabLayoutconViewPager.

E un altro ViewPagerdentro quel frammento. La prima volta tutto funziona bene, ma quando cambio scheda e torno indietro, alcuni dei miei frammenti sono diventati vuoti.


1
Buona risposta. Mi ha aiutato.
Thirumalvalavan


1

Abbiamo aggirato questo problema reimplementando gli elementi del cercapersone della vista come viste standard anziché frammenti e cambiando l'adattatore di conseguenza.


puoi provare a rimuovere la funzione isViewFromObject (Visualizza vista, Oggetto oggetto)
Mina Samy

Deve esserci un modo migliore ....: / anche se più mi addentro su Android e meno maturo mi rendo conto che lo è.
StackOverflowed

1
I frammenti nidificati non sono supportati , quindi la reimplementazione con la visualizzazione standard sembra la buona strada da percorrere.
Sylphe

Sto lottando con un problema simile. Ho provato a utilizzare PagerAdapter invece di FragmentAdapter, ma riscontro lo stesso problema. Per favore aiutatemi !
Gaurav Arora

Se si desidera utilizzare i frammenti nidificate è possibile utilizzare l'adattatore ho fornito in questa risposta: stackoverflow.com/questions/7700226/...
Slickelito

1

Ho riscontrato lo stesso problema su Xamarin Android con una schermata vuota la seconda volta .. L'impostazione di quanto segue ha risolto il problema per me.

viewPager.SaveFromParentEnabled = false;

0

Puoi anche inizializzare l'adattatore per i casi in cui si verifica questo errore quando la tua app viene ridotta a icona e successivamente richiamata.

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}

0

Ho avuto la stessa cosa, la seconda volta che chiamo l'adattatore cercapersone, la vista figlio restituisce una NullPointerException. E cambiare l'adattatore in FragmentStatePagerAdapter risolve anche il mio problema.


0

Cambia FragmentPagerAdapterin FragmentStatePagerAdapter uso getChildFragmentManager()invece digetFragmentManager()

getChildFragmentManager()- perché secondo la documentazione, restituirà un FragmentManager privato per posizionare e gestire i frammenti all'interno di questo frammento. Nel frattempo getFragmentManager()restituirà il FragmentManager per interagire con i frammenti associati a questa attività


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.