2012-06-12 27 views
7

Aquí hay una aplicación para Android sencilla que he creado para demostrar mi problema:onCreateOptionsMenu androide llamado dos veces al restaurar el estado

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

Fragmento:

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

diseño es sólo un LinearLayout para volcar el fragmento en :

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

Muy simple ¿no? Cuando lo ejecuto me da el siguiente resultado como se esperaba:

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 

Ahora, cuando gira el teléfono me sale un comportamiento extraño:

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 

¿Por qué la actividad onCreateOptionMenu y el fragmento onCreateOptionsMenu llama dos veces? Si quito el menú de opciones a partir del fragmento consigo 1 llamada a la actividad onCreateOptionsMenu como se esperaba:

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 

que no entienden esto y nadie más parece haber encontrado con este problema. El verdadero problema es que mi SearchView no puede recuperar su estado en el cambio de configuración (rotar el teléfono) porque onCreateOptionMenu se está llamando dos veces. La primera vez parece tener su estado, pero la segunda vez se borra y restablece. No puedo entender lo que estoy haciendo mal.

Gracias de antemano.

+0

Creo que su mejor oportunidad sería la de obtener una bodega del código fuente y el paso a través de él con el depurador. Bien podría ser un error en Android. –

+0

No he progresado en este problema. He recorrido el código pero no estoy lo suficientemente familiarizado con el ciclo de vida del fragmento/actividad detrás de las escenas para saber qué está pasando o cuál podría ser el problema. Tengo una solución en este momento que es bastante "hacky", pero me estoy moviendo. Si alguien viene con una respuesta, házmelo saber. ¡Gracias! – Dave

+0

Tengo exactamente el mismo problema. 'onCreateOptionMenu' y' onPrepareOptionsMenu' se invocan dos veces y la segunda vez que restablecen el estado del menú. No he encontrado una solución todavía :( –

Respuesta

5

Creo que encontré la respuesta a este problema.

Tome un vistazo a esto:

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

El problema parece estar relacionado con el hecho de que Android no destruye el fragmento cuando se destruye la actividad (cuando se gira el dispositivo).

Básicamente ha añadido:

setRetainInstance(true); 

a mi constructor de fragmentos y desaparecer el problema resuelto.

Espero que ayude!

+3

Sí, muchas gracias. Esto resolvió mi problema. Curiosamente, la actividad también tiene este problema si un fragmento participa en el menú de opciones y no llama a setRetainInstance (verdadero) , incluso si SearchView es agregado por la actividad. Si elimina setHasOptionsMenu del fragmento, la actividad SearchView se comporta normalmente. Creo que debido a que el fragmento recién agregado hace que las actividades en CreateOptionsMenu sean llamadas nuevamente. – Dave

2

@Gerardo Contijoch respuesta es engañosa, a excepción de un hecho:

En su ejemplo tanto Activity y Fragment se destruyen después de la rotación y creados de nuevo. Es por eso que onCreateOptionsMenu() se llama dos veces. Este es el comportamiento correcto y esperado.

Por setRetainInstance(true) le dice a Android que no destruya el fragmento. Esto puede resultar útil en el caso de un fragmento sin UI que no contenga ningún contexto de Actividad (útil para la coordinación de AsyncTasks y algunas otras cosas similares a las del servicio).

En otros casos, esto puede provocar fugas de memoria, que debe evitar.

0

He menú simplemente limpiado antes de inflar y trabaja

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

} 
Cuestiones relacionadas