2012-06-12 14 views
7

Ecco una semplice applicazione Android che ho creato per dimostrare il mio problema:onCreateOptionsMenu androide chiamato due volte durante il ripristino dello stato

public class OptionMenuTest extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.d("test", "create activity"); 
     setContentView(R.layout.options_layout); 
     if(getFragmentManager().findFragmentByTag("frag") == null) { 
      getFragmentManager().beginTransaction().add(R.id.option_fragment_container, new OptionMenuFragment(), "frag").commit(); 
     } 

    } 

    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     Log.d("test", "saving Activity state"); 
     super.onSaveInstanceState(outState); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     Log.d("test", "create Activity options menu"); 
     menu.add("activity"); 
     return true; 
    } 
} 

Frammento:

public class OptionMenuFragment extends Fragment { 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.d("test", "create fragment"); 
     setHasOptionsMenu(true); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     TextView tv = new TextView(getActivity()); 
     tv.setText("Hello world"); 
     Log.d("test", "create fragment view"); 
     return tv; 
    } 

    @Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     menu.add("fragment"); 
     Log.d("test", "create fragment options menu"); 
    } 
} 

layout è solo un LinearLayout per scaricare il frammento in :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/option_fragment_container" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    > 
</LinearLayout> 

Molto semplice, vero? Quando l'eseguo ottengo il seguente output come previsto:

06-12 15:42:51.415: D/test(957): create activity 
06-12 15:42:51.446: D/test(957): create fragment 
06-12 15:42:51.446: D/test(957): create fragment view 
06-12 15:42:51.446: D/test(957): create Activity options menu 
06-12 15:42:51.446: D/test(957): create fragment options menu 

Ora, quando ho ruotare il telefono ho un po 'strano comportamento:

06-12 15:43:11.251: D/test(957): saving Activity state 
06-12 15:43:11.290: D/test(957): create fragment 
06-12 15:43:11.290: D/test(957): create activity 
06-12 15:43:11.306: D/test(957): create fragment view 
06-12 15:43:11.306: D/test(957): create Activity options menu 
06-12 15:43:11.306: D/test(957): create fragment options menu 
06-12 15:43:11.306: D/test(957): create Activity options menu 
06-12 15:43:11.306: D/test(957): create fragment options menu 

Perché l'attività onCreateOptionMenu e frammento onCreateOptionsMenu chiamato due volte? Se rimuovo il menu delle opzioni dal frammento ricevo 1 chiamata all'attività onCreateOptionsMenu come previsto:

06-12 15:50:03.610: D/test(1076): create fragment 
06-12 15:50:03.610: D/test(1076): create fragment view 
06-12 15:50:03.813: D/test(1076): create Activity options menu 
06-12 15:50:08.392: D/test(1076): saving Activity state // <-- rotate happens here 
06-12 15:50:08.446: D/test(1076): create fragment 
06-12 15:50:08.446: D/test(1076): create activity 
06-12 15:50:08.462: D/test(1076): create fragment view 
06-12 15:50:08.470: D/test(1076): create Activity options menu 

non capisco questo e nessun altro sembra aver riscontrato questo problema. Il vero problema è che il mio SearchView non è in grado di ripristinare il suo stato in caso di modifica della configurazione (il telefono ruota) perché il onCreateOptionMenu viene chiamato due volte. La prima volta sembra avere lo stato ma la seconda volta viene cancellato e ripristinato. Non sono in grado di capire cosa sto facendo male.

Grazie in anticipo.

+0

penso che il vostro colpo migliore sarebbe quella di ottenere una sospensione del codice sorgente e passo attraverso di essa con il debugger. Potrebbe benissimo essere un bug in Android. –

+0

Non ho fatto alcun progresso su questo problema. Ho passato il codice ma non ho familiarità con il ciclo di vita di frammento/attività dietro le quinte per sapere cosa sta succedendo o quale potrebbe essere il problema. In questo momento ho una soluzione che è abbastanza "hacky", ma mi sto muovendo. Se qualcuno ha una risposta, fammi sapere. Grazie! – Dave

+0

Ho lo stesso identico problema. 'onCreateOptionMenu' e' onPrepareOptionsMenu' vengono chiamati due volte e la seconda volta ripristinano lo stato del menu. Non ho ancora trovato una soluzione :( –

risposta

5

Penso di aver trovato la risposta a questo problema.

Date un'occhiata a questo:

https://stackoverflow.com/a/7225296/48468

Il problema sembra essere legato al fatto che Android non distrugge il frammento quando l'attività viene distrutta (quando viene ruotato il dispositivo).

Fondamentalmente ho aggiunto:

setRetainInstance(true); 

alla mia costruttore frammento e il problema andare risolto.

Spero che aiuti!

+3

Sì! Grazie mille, questo ha risolto il mio problema È interessante notare che l'attività presenta questo problema anche se un frammento partecipa al menu delle opzioni e non chiama setRetainInstance (true) , anche se SearchView viene aggiunto dall'attività.Se si rimuove setHasOptionsMenu dal frammento, l'attività SearchView si comporta normalmente.Penso perché il frammento appena aggiunto fa sì che le attività suCreateOptionsMenu vengano richiamate di nuovo. – Dave

2

@Gerardo Contijoch risposta è fuorviante, tranne che per un fatto:

Nel tuo esempio sia Activity e Fragment vengono distrutti in seguito a rotazione e ha creato di nuovo. Ecco perché lo onCreateOptionsMenu() viene chiamato due volte. Questo è un comportamento corretto e atteso.

Entro setRetainInstance(true) hai detto a Android di non distruggere il frammento. Ciò potrebbe rivelarsi utile in caso di frammento senza UI che non contiene il contesto di Attività (utile per il coordinamento AsyncTasks e altri tipi di servizi simili).

In altri casi, frammentare questo potenziale porta alla perdita di memoria, che si deve evitare.

0

ho appena menù eliminato prima di gonfiare e lavora

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     menu.clear(); 
     inflater.inflate(R.menu.call_menu, menu); 
     super.onCreateOptionsMenu(menu, inflater); 

} 
Problemi correlati