Come posso mantenere lo stato del frammento quando aggiunto allo stack posteriore?


160

Ho scritto un'attività fittizia che passa tra due frammenti. Quando passi da FragmentA a FragmentB, FragmentA viene aggiunto allo stack posteriore. Tuttavia, quando torno a FragmentA (premendo indietro), viene creato un frammento A completamente nuovo e lo stato in cui si trovava viene perso. Ho la sensazione di cercare la stessa cosa di questa domanda, ma ho incluso un esempio di codice completo per aiutare a risolvere il problema:

public class FooActivity extends Activity {
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentA());
    transaction.commit();
  }

  public void nextFragment() {
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentB());
    transaction.addToBackStack(null);
    transaction.commit();
  }

  public static class FragmentA extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      final View main = inflater.inflate(R.layout.main, container, false);
      main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          ((FooActivity) getActivity()).nextFragment();
        }
      });
      return main;
    }

    @Override public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      // Save some state!
    }
  }

  public static class FragmentB extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      return inflater.inflate(R.layout.b, container, false);
    }
  }
}

Con alcuni messaggi di registro aggiunti:

07-05 14:28:59.722 D/OMG     ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG     ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG     ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG     ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG     ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG     ( 1260): FragmentA.onCreateView

Non chiama mai FragmentA.onSaveInstanceState e crea un nuovo FragmentA quando rispondi. Tuttavia, se sono su FragmentA e blocco lo schermo, FragmentA.onSaveInstanceState viene chiamato. Così strano ... mi sbaglio nell'aspettarmi che un frammento aggiunto allo stack posteriore non abbia bisogno di essere ricreato? Ecco cosa dicono i documenti :

Considerando che, se si chiama addToBackStack () quando si rimuove un frammento, il frammento viene arrestato e riprenderà se l'utente torna indietro.


3
@ Jan-Henk E le cose che devono essere recuperate? Ad esempio, la posizione di scorrimento di a ListView. Sembra un salto troppo lungo per collegare un listener di scorrimento e aggiornare una variabile di istanza.
Jake Wharton,

2
@JakeWharton Sono d'accordo che dovrebbe essere più semplice, ma per quanto ne so non c'è modo di aggirare questo perché onCreateView viene chiamato quando un frammento viene ripristinato dallo backstack. Ma potrei sbagliarmi :)
Jan-Henk il

1
onCreate non viene chiamato. Quindi a quanto pare sta riutilizzando la stessa istanza ma richiamando di nuovo suCreateView? Noioso. Immagino di poter semplicemente memorizzare nella cache il risultato di onCreateView e restituire la vista esistente se onCreateView viene richiamato di nuovo.
Eric

1
Esattamente quello che stavo cercando da ore. Puoi pubblicare come hai ottenuto questo risultato usando la variabile di istanza?
Uma,

1
Di recente ho quindi iniziato la mia implementazione in github.com/frostymarvelous/Folio e ho riscontrato un problema. Sono in grado di creare circa 5 pagine / frammenti complessi prima di iniziare a ottenere arresti anomali OOM. Questo è ciò che mi ha portato qui. Nascondere e mostrare non è semplicemente abbastanza. Le viste sono troppo ricche di memoria.
gelido

Risposte:


120

Se si ritorna a un frammento dallo stack posteriore, questo non ricrea il frammento ma riutilizza la stessa istanza e inizia con onCreateView()il ciclo di vita del frammento, vedere Ciclo di vita del frammento .

Quindi, se si desidera memorizzare lo stato, è necessario utilizzare le variabili di istanza e non fare affidamento su onSaveInstanceState().


32
L'attuale versione della documentazione contraddice questa affermazione. Il diagramma di flusso dice ciò che affermi, ma il testo nell'area principale della pagina dice che onCreateView () viene chiamato solo la prima volta che viene visualizzato il frammento: developer.android.com/guide/components/fragments.html Sto combattendo questo problema ora, e non vedo alcun metodo chiamato quando si restituisce un frammento dallo backstack. (Android 4.2)
Colin M.,

10
Ho provato a registrarne il comportamento. OnCreateView () viene sempre chiamato quando viene visualizzato il frammento.
princepiero,

4
@ColinM. Qualche soluzione al problema?
bufera di neve

9
Questo non funziona per me. Le variabili della mia istanza sono nulle al ritorno al frammento! Come posso salvare lo stato?
Don Rhummy,

5
quindi se non dovessimo inoltrare l'istanza di salvataggio come dovremmo salvare lo stato e i dati del frammento?
Mahdi,

80

Rispetto a Apple UINavigationControllere UIViewController, Google non funziona bene nell'architettura del software Android. E il documento di Android suFragment non aiuta molto.

Quando si immette FragmentB da FragmentA, l'istanza FragmentA esistente non viene distrutta. Quando premi Back in FragmentB e ritorni su FragmentA, non creiamo una nuova istanza di FragmentA. onCreateView()Verrà chiamata l'istanza di FragmentA esistente .

La cosa fondamentale è che non dovremmo gonfiare di nuovo la vista in FragmentA onCreateView(), perché stiamo usando l'istanza esistente di FragmentA. Dobbiamo salvare e riutilizzare rootView.

Il seguente codice funziona bene. Non solo mantiene lo stato del frammento, ma riduce anche il carico di RAM e CPU (perché gonfiamo il layout solo se necessario). Non posso credere che il codice e il documento di esempio di Google non ne parlino mai, ma gonfiano sempre il layout .

Versione 1 (Non utilizzare la versione 1. Utilizzare la versione 2)

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // (it will be added back).
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        return _rootView;
    }
}

------ Aggiornamento del 3 maggio 2005: -------

Come menzionato nei commenti, a volte _rootView.getParent()è nullo in onCreateView, che causa l'arresto anomalo. La versione 2 rimuove _rootView in onDestroyView (), come suggerito dell116. Testato su Android 4.0.3, 4.4.4, 5.1.0.

Versione 2

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // in onDestroyView() (it will be added back).
        }
        return _rootView;
    }

    @Override
    public void onDestroyView() {
        if (_rootView.getParent() != null) {
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        super.onDestroyView();
    }
}

AVVERTIMENTO!!!

Questo è un HACK! Anche se lo sto usando nella mia app, devi testare e leggere attentamente i commenti.


38
Tenere un riferimento alla radice di tutto il frammento è una cattiva idea dell'IMO. Se si aggiungono continuamente diversi frammenti a uno backstack e tutti mantengono il suo rootview (che ha un ingombro di memoria abbastanza grande), allora c'è un'alta possibilità che tu finisca con OutOfMemoryError poiché tutti i frammenti contengono riferimenti rootview e GC non può collezionalo. Penso che l'approccio migliore sia gonfiare continuamente la vista (e lasciare che il sistema Android gestisca la sua creazione / distruzione della vista) e onActivityCreated / onViewCreated controlla se i tuoi dati sono nulli. Se sì, caricalo, altrimenti imposta i dati su viste.
traninho,

15
Non farlo! Quando viene creata la gerarchia di visualizzazione del frammento, contiene un riferimento interno all'attività che conteneva il frammento in quel momento. Quando si verifica una modifica della configurazione, l'attività viene spesso ricreata. Riutilizzando il vecchio layout, l'attività zombi viene mantenuta in memoria insieme agli oggetti a cui fa riferimento. Sprecare memoria in questo modo ostacola le prestazioni e rende la tua app la migliore candidata per la chiusura immediata quando non in primo piano.
Krylez,

4
@AllDayAmazing Questo è un buon punto. Ad essere sincero, sono molto confuso in questo momento. Qualcuno può provare a spiegare perché tenere un riferimento a rootview di un frammento non è ok, ma tenere un riferimento solo per qualsiasi figlio di rootview (che ha comunque un riferimento a rootview) è ok?
Traninho,

2
STAI LONTANO DA QUESTO A meno che tu non voglia perdere 5 ore a scoprire cosa sta cacciando il tuo codice ..... quindi solo per scoprire che questa è la causa. Ora devo refactificare un sacco di cose perché ho usato questo trucco. È molto meglio usare fragmentTransaction.add se si desidera mantenere intatta l'interfaccia utente del frammento quando si visualizza un altro (anche in cima). fragmentTransaction.replace () ha lo scopo di distruggere le viste del frammento ..... non combattere il sistema.
dell116,

2
@VinceYuan - Ho provato con l'ultima libreria v7-appcompat su Android 5.1 e questo ha lasciato 6 istanze di un frammento che avrebbe dovuto essere rimosso nel FragmentManager della mia attività. Anche se il GC lo gestirà correttamente (cosa che non credo lo farà) questo sta causando uno sforzo inutile sulla memoria della tua app e del dispositivo in generale. Il semplice utilizzo di .add () elimina completamente la necessità di tutto questo codice hacky. Fare questo è completamente contro ciò che usare FragmentTransaction.replace () doveva fare in primo luogo.
dell116,

53

Immagino che ci sia un modo alternativo per ottenere ciò che stai cercando. Non dico che è una soluzione completa, ma ha servito allo scopo nel mio caso.

Quello che ho fatto è stato invece di sostituire il frammento che ho appena aggiunto il frammento di destinazione. Quindi in pratica userete add()invece il metodo replace().

Cos'altro ho fatto. Nascondo il mio frammento attuale e lo aggiungo anche allo zaino.

Quindi si sovrappone al nuovo frammento sul frammento attuale senza distruggere la sua vista (controlla che il suo onDestroyView()metodo non venga chiamato. Inoltre aggiungendolo a backstatemi dà il vantaggio di riprendere il frammento.

Ecco il codice:

Fragment fragment=new DestinationFragment();
FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment);
ft.hide(SourceFragment.this);
ft.addToBackStack(SourceFragment.class.getName());
ft.commit();

Il sistema AFAIK chiama solo onCreateView()se la vista è distrutta o non creata. Ma qui abbiamo salvato la vista non rimuovendola dalla memoria. Quindi non creerà una nuova vista.

E quando torni da Frammento di destinazione, si aprirà l'ultimo FragmentTransaction frammento superiore rimuovendo che farà apparire la vista più in alto (di SourceFragment) sullo schermo.

COMMENTO: Come ho già detto, non è una soluzione completa in quanto non rimuove la vista del frammento di Source e quindi occupa più memoria del solito. Tuttavia, servire allo scopo. Inoltre, stiamo usando un meccanismo totalmente diverso di nascondere la vista invece di sostituirlo che non è tradizionale.

Quindi non è proprio per come mantieni lo stato, ma per come mantieni la vista.


Nel mio caso, aggiungendo un frammento invece di sostituire causa problemi quando si utilizza il polling o qualsiasi altro tipo di richiesta Web, nel frammento viene utilizzato. Voglio mettere in pausa questo polling nel frammento A quando viene aggiunto il frammento B. Qualche idea su questo?
Uma,

Come stai usando il polling in FirstFragment? Devi farlo manualmente poiché entrambi i frammenti rimangono in memoria, quindi puoi usare le loro istanze per eseguire l'azione necessaria. Qual è l'indizio, genera un evento nell'attività principale che fa qualcosa quando aggiungi il secondo frammento. Spero che questo possa aiutare.
Kaushal trivedi,

1
Grazie per l'indizio =). Ho fatto questo. Ma è questo l'unico modo per farlo? E un modo appropriato? Inoltre, quando premo il pulsante Home e riavvio l'applicazione, tutti i frammenti si attivano nuovamente. Supponiamo che io sia qui nel frammento B in questo modo. Activity A{Fragment A --> Fragment B}quando riavvio l'applicazione dopo aver premuto il pulsante home, onResume()vengono chiamati entrambi i frammenti e quindi iniziano il polling. Come posso controllarlo?
Uma,

1
Sfortunatamente non puoi, il sistema non funziona in questo modo in modo normale, considererà entrambi i frammenti come figlio diretto dell'attività. Sebbene servisse allo scopo di mantenere lo stato del frammento, altre cose normali diventano molto difficili da gestire. scoperto tutti questi problemi, ora il mio suggerimento è di non andare per questo. Scusa.
Kaushal trivedi

1
Certo, alla fine dirò di non seguire questo approccio fino a quando non troverai un'altra soluzione, perché è difficile da gestire.
Kaushal trivedi,

7

Suggerirei una soluzione molto semplice.

Prendi la variabile di riferimento Visualizza e imposta la vista in OnCreateView. Controlla se la vista esiste già in questa variabile, quindi restituisci la stessa vista.

   private View fragmentView;

   public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        if (fragmentView != null) {
            return fragmentView;
        }
        View view = inflater.inflate(R.layout.yourfragment, container, false);
        fragmentView = view;
        return view;
    }

1
C'è una possibilità di perdita di memoria se non si rimuoveva la variabile 'fragmentView' in onDestroy ()
Arun PM

@ArunPM quindi come rimuovere fragmentView in onDestroy ()? if (_rootView.getParent() != null) { ((ViewGroup)_rootView.getParent()).removeView(_rootView); }è appropriato per cancellare la memoria?
Mehmet Gür

1
@ MehmetGür Sto usando questa soluzione molte volte. Fino ad ora non ho riscontrato alcun errore di perdita di memoria. Ma puoi usare la soluzione ArunPM se vuoi. Penso che stia dicendo di impostare fragmentView su null nel metodo OnDestroy ().
Mandeep Singh,

1
Sto usando LeakCanary per rilevare perdite di memoria e problemi di perdita quando ho seguito questo metodo. Ma come ha menzionato @Mandeep Sigh nel commento, possiamo superare questo problema assegnando nullalla fragmentView variabile nel onDestroy()metodo.
Arun PM

1
Per quanto ne so, quando un frammento viene distrutto, la vista associata al frammento viene cancellata onDestroyView(). Questa cancellazione non sta avvenendo per la nostra variabile della vista di backup (qui fragmentView ) e causerà una perdita di memoria quando il frammento torna impilato / distrutto. Puoi trovare lo stesso riferimento in [Cause comuni per perdite di memoria] ( square.github.io/leakcanary/fundamentals/… ) nell'introduzione di LeakCanery.
Arun PM

6

Ho riscontrato questo problema in un frammento contenente una mappa, che contiene troppi dettagli di configurazione per salvare / ricaricare. La mia soluzione è stata sostanzialmente quella di mantenere attivo questo frammento per tutto il tempo (in modo simile a quanto menzionato da @kaushal).

Supponi di avere l'attuale frammento A e desideri visualizzare il frammento B. Riassumendo le conseguenze:

  • sostituire () - rimuovere il frammento A e sostituirlo con il frammento B. Il frammento A verrà ricreato una volta portato di nuovo in primo piano
  • add () - (create and) aggiunge un frammento B e si sovrappone al frammento A, che è ancora attivo in background
  • remove () - può essere usato per rimuovere il frammento B e tornare ad A. Il frammento B verrà ricreato quando chiamato in seguito

Quindi, se vuoi mantenere entrambi i frammenti "salvati", basta attivarli usando hide () / show ().

Pro : metodo facile e semplice per mantenere in esecuzione più frammenti
Contro : usi molta più memoria per mantenerli tutti in esecuzione. Potrebbero verificarsi problemi, ad esempio la visualizzazione di molte bitmap di grandi dimensioni


puoi dirmi quando rimuoviamo il frammento b e torniamo ad A, quale metodo viene chiamato nel frammento A? voglio intervenire quando rimuoviamo il frammento B.
Google

5

onSaveInstanceState() viene chiamato solo in caso di modifica della configurazione.

Dal momento che il passaggio da un frammento a un altro non è stato apportato alcun cambiamento di configurazione, quindi nessuna chiamata a onSaveInstanceState() è presente . Quale stato non viene salvato? Puoi specificare?

Se inserisci del testo in EditText, questo verrà salvato automaticamente. Qualsiasi elemento dell'interfaccia utente senza ID è l'elemento il cui stato di visualizzazione non deve essere salvato.


onSaveInstanceState()viene anche chiamato quando il sistema distrugge l'attività perché manca di risorse.
Marcel Bro,

0

Qui, poiché onSaveInstanceStatenel frammento non viene chiamato quando si aggiunge il frammento nel backstack. Il ciclo di vita del frammento nel backstack quando ripristinato inizia onCreateViewe termina onDestroyViewmentre onSaveInstanceStateviene chiamato tra onDestroyViewe onDestroy. La mia soluzione è creare la variabile di istanza e init in onCreate. Codice di esempio:

private boolean isDataLoading = true;
private ArrayList<String> listData;
public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     isDataLoading = false;
     // init list at once when create fragment
     listData = new ArrayList();
}

E check in onActivityCreated:

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if(isDataLoading){
         fetchData();
    }else{
         //get saved instance variable listData()
    }
}

private void fetchData(){
     // do fetch data into listData
}

0
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener()
    {
        @Override
        public void onBackStackChanged()
        {
            if (getSupportFragmentManager().getBackStackEntryCount() == 0)
            {
                //setToolbarTitle("Main Activity");
            }
            else
            {
                Log.e("fragment_replace11111", "replace");
            }
        }
    });


YourActivity.java
@Override
public void onBackPressed()
{
 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.Fragment_content);
  if (fragment instanceof YourFragmentName)
    {
        fragmentReplace(new HomeFragment(),"Home Fragment");
        txt_toolbar_title.setText("Your Fragment");
    }
  else{
     super.onBackPressed();
   }
 }


public void fragmentReplace(Fragment fragment, String fragment_name)
{
    try
    {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.Fragment_content, fragment, fragment_name);
        fragmentTransaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
        fragmentTransaction.addToBackStack(fragment_name);
        fragmentTransaction.commitAllowingStateLoss();
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

0

Il mio problema era simile ma mi ha superato senza mantenere vivo il frammento. Supponiamo di avere un'attività che ha 2 frammenti: F1 e F2. F1 viene avviato inizialmente e consente di dire che contiene alcune informazioni utente e quindi su una condizione F2 si apre chiedendo all'utente di inserire un attributo aggiuntivo : il loro numero di telefono. Successivamente, vuoi che quel numero di telefono ritorni su F1 e completi la registrazione, ma ti rendi conto che tutte le informazioni utente precedenti sono state perse e non hai i loro dati precedenti. Il frammento viene ricreato da zero e anche se si sono salvate queste informazioni nel onSaveInstanceStatebundle, viene restituito null onActivityCreated.

Soluzione: salvare le informazioni richieste come variabile di istanza nell'attività di chiamata. Quindi passa quella variabile di istanza nel tuo frammento.

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    Bundle args = getArguments();

    // this will be null the first time F1 is created. 
    // it will be populated once you replace fragment and provide bundle data
    if (args != null) {
        if (args.get("your_info") != null) {
            // do what you want with restored information
        }
    }
}

Quindi, seguendo il mio esempio: prima di visualizzare F2, salvo i dati utente nella variabile di istanza usando un callback. Quindi avvio F2, l'utente inserisce il numero di telefono e preme Salva. Uso un altro callback in attività, raccolgo queste informazioni e sostituisco il mio frammento F1, questa volta ha i dati del bundle che posso usare.

@Override
public void onPhoneAdded(String phone) {
        //replace fragment
        F1 f1 = new F1 ();
        Bundle args = new Bundle();
        yourInfo.setPhone(phone);
        args.putSerializable("you_info", yourInfo);
        f1.setArguments(args);

        getFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainer, f1).addToBackStack(null).commit();

    }
}

Ulteriori informazioni sui callback sono disponibili qui: https://developer.android.com/training/basics/fragments/communicating.html


0

primo : basta usare il metodo add invece di sostituire il metodo della classe FragmentTransaction quindi devi aggiungere secondFragment per impilare con il metodo addToBackStack

secondo : al back click devi chiamare popBackStackImmediate ()

Fragment sourceFragment = new SourceFragment ();
final Fragment secondFragment = new SecondFragment();
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.add(R.id.child_fragment_container, secondFragment );
ft.hide(sourceFragment );
ft.addToBackStack(NewsShow.class.getName());
ft.commit();
                                
((SecondFragment)secondFragment).backFragmentInstanceClick = new SecondFragment.backFragmentNewsResult()
{
        @Override
        public void backFragmentNewsResult()
        {                                    
            getChildFragmentManager().popBackStackImmediate();                                
        }
};

0

Sostituisci un frammento usando il seguente codice:

Fragment fragment = new AddPaymentFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame, fragment, "Tag_AddPayment")
                .addToBackStack("Tag_AddPayment")
                .commit();

OnBackPressed () dell'attività è:

  @Override
public void onBackPressed() {
    android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 1) {

        fm.popBackStack();
    } else {


        finish();

    }
    Log.e("popping BACKSTRACK===> ",""+fm.getBackStackEntryCount());

}

0
Public void replaceFragment(Fragment mFragment, int id, String tag, boolean addToStack) {
        FragmentTransaction mTransaction = getSupportFragmentManager().beginTransaction();
        mTransaction.replace(id, mFragment);
        hideKeyboard();
        if (addToStack) {
            mTransaction.addToBackStack(tag);
        }
        mTransaction.commitAllowingStateLoss();
    }
replaceFragment(new Splash_Fragment(), R.id.container, null, false);

1
Grazie per questo frammento di codice, che potrebbe fornire un aiuto limitato e immediato. Una spiegazione adeguata migliorerebbe notevolmente il suo valore a lungo termine mostrando perché questa è una buona soluzione al problema e la renderebbe più utile ai futuri lettori con altre domande simili. Si prega di modificare la risposta di aggiungere qualche spiegazione, tra le ipotesi che hai fatto.
Machavity

0

Soluzione perfetta che trova il vecchio frammento nello stack e lo carica se esiste nello stack.

/**
     * replace or add fragment to the container
     *
     * @param fragment pass android.support.v4.app.Fragment
     * @param bundle pass your extra bundle if any
     * @param popBackStack if true it will clear back stack
     * @param findInStack if true it will load old fragment if found
     */
    public void replaceFragment(Fragment fragment, @Nullable Bundle bundle, boolean popBackStack, boolean findInStack) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        String tag = fragment.getClass().getName();
        Fragment parentFragment;
        if (findInStack && fm.findFragmentByTag(tag) != null) {
            parentFragment = fm.findFragmentByTag(tag);
        } else {
            parentFragment = fragment;
        }
        // if user passes the @bundle in not null, then can be added to the fragment
        if (bundle != null)
            parentFragment.setArguments(bundle);
        else parentFragment.setArguments(null);
        // this is for the very first fragment not to be added into the back stack.
        if (popBackStack) {
            fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        } else {
            ft.addToBackStack(parentFragment.getClass().getName() + "");
        }
        ft.replace(R.id.contenedor_principal, parentFragment, tag);
        ft.commit();
        fm.executePendingTransactions();
    }

usalo come

Fragment f = new YourFragment();
replaceFragment(f, null, boolean true, true); 
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.