Android onCreateOptionsMenu llamó dos veces al restaurar el estado

Aquí hay una aplicación de Android simple que he creado para demostrar mi problema:

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

El diseño es solo 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 sencillo verdad? Cuando lo ejecuto, obtengo 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 giro el teléfono, obtengo 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é se llama dos veces a la actividad onCreateOptionMenu y al fragmento onCreateOptionsMenu? Si elimino el menú de opciones del fragmento, recibo 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

No entiendo esto y nadie más parece haber encontrado este problema. El problema real es que mi SearchView no puede recuperar su estado en el cambio de configuración (rotación del teléfono) porque onCreateOptionMenu se llama dos veces. La primera vez parece tener su estado, pero la segunda vez se borra y se reinicia. No soy capaz de averiguar qué estoy haciendo mal.

Gracias de antemano.

preguntado el 12 de junio de 12 a las 20:06

Creo que su mejor opción sería obtener el código fuente y revisarlo con el depurador. Muy bien podría ser un error en Android. -

No he hecho ningún progreso en este problema. Revisé el código, pero no estoy lo suficientemente familiarizado con el ciclo de vida del fragmento/actividad detrás de escena para saber qué está pasando o cuál podría ser el problema. Tengo una solución en este momento que es bastante "incómoda", pero sigo adelante. Si a alguien se le ocurre una respuesta, hágamelo saber. ¡Gracias! -

Tengo exactamente el mismo problema. onCreateOptionMenu y onPrepareOptionsMenu me llaman dos veces y la segunda vez restablecen el estado del menú. Aún no he encontrado una solución :( -

3 Respuestas

Creo que encontré la respuesta a este problema.

Eche 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 agregué:

setRetainInstance(true);

a mi constructor de fragmentos y el problema se resolvió.

¡Espero eso ayude!

contestado el 23 de mayo de 17 a las 13:05

¡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(true), incluso si la actividad agrega SearchView. Si elimina setHasOptionsMenu del fragmento, la actividad SearchView se comporta normalmente. Creo que porque el fragmento recién agregado hace que se vuelva a llamar a las actividades onCreateOptionsMenu. - David

La respuesta de @Gerardo Contijoch es engañosa, excepto por un hecho:

En tu ejemplo ambos Activity y Fragment se destruyen al rotar y se crean de nuevo. Es por eso que onCreateOptionsMenu() se llama dos veces. Este es el comportamiento correcto y esperado.

By setRetainInstance(true) le dices a Android que no destruya el fragmento. Esto puede resultar útil en el caso de un fragmento sin interfaz de usuario que no tenga contexto de Actividad (útil para la coordinación de AsyncTasks y algunas otras cosas similares a servicios).

En otros casos, fragmentar esto conduce potencialmente a una fuga de memoria, que debe evitar.

Respondido 10 Feb 15, 13:02

Acabo de borrar el menú antes de inflar y funciona

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

 }

contestado el 02 de mayo de 16 a las 14:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.