OnClick o onItemClick mientras pausan resultados en "IllegalStateException: No se puede realizar esta acción después de onSaveInstanceState"

Tengo un TabActivity que recibe 5x FragmentActivity . Varios de ellos contienen botones o listas que, en su onClick() o onItemClick() , crean y empujan un nuevo fragmento.

En su mayor parte, esto funciona bien, pero si las cosas son un poco insensibles, o un probador hace algo tonto (presione y mantenga un botón o elemento de la lista, utilice un dedo diferente para cambiar las pestañas, a continuación, suelte el botón / lista – 100% reproducible), obtengo el evento de clic mucho después de que la actividad se ha detenido y guardado. Vea el fragmento de registro:

 10-30 17:05:16.258 3415 3415 D BKC DEBUG: More.onSaveInstanceState() 10-30 17:05:16.258 3415 3415 D BKC DEBUG: MoreFragment.onPause() 10-30 17:05:17.309 3415 3415 D BKC DEBUG: MoreFragment.onItemClick() 

Después de leer este artículo y varias preguntas StackOverflow sobre pérdida de estado de fragmento, no veo una buena respuesta a cómo solucionarlo.

  • Usar commitAllowingStateLoss() (incondicionalmente) es una solución que podría ocultar errores reales.
  • No estoy seguro de que anular el registro de OnClickListener s y OnItemClickListener s en onSaveInstanceState 100% evitar esto, y es una especie de PITA hacer eso por cada botón en cada fragmento.
  • Alguien sugirió comprobar el fragmento pertinente isAdded() , pero puedo confirmar que no funciona.
  • Podría establecer una bandera en onSaveInstanceState() y onRestoreInstanceState() y comprobar que en onClick (), pero de nuevo, eso es sólo un kludge. EDIT: Oh, el fragmento no tiene onRestoreInstanceState() , pero puedo girar la bandera en onResume() o lo que sea.

¿Hay una solución correcta para esto que me falta, o debería ir con mi kludge de elección?

Después de pensar un poco más, creo que commitAllowingStateLoss() es de hecho la respuesta correcta para este caso. Sabemos que estamos en el controlador onClick() o onItemClick() , así que si la pérdida de estado podría ocurrir, sabemos que es debido a este agujero que permite hacer clic en eventos después de la onSaveInstanceState() .

En mis pruebas casuales, el nuevo fragmento de hecho aparecerá cuando regrese a la pestaña correspondiente, ya que nada fue realmente derribado. Eso es un poco sorprendente para el usuario, pero probablemente aceptable para este caso de borde.

Creo que una solución más elegante aquí sería simplemente ignorar el evento de clic. Configure una bandera booleana muy simple en su BaseActivity para realizar un seguimiento cuando su actividad está en pausa:

 class BaseActivity extends BaseFragmentActivity { private boolean isPaused; @Override protected void onPause() { isPaused = true; super.onPause(); } @Override protected void onResume() { super.onResume(); isPaused = false; } public boolean isPaused() { return isPaused; } } 

Siempre que obtenga un evento de clic, simplemente compruebe si su actividad está en pausa. Si lo es, entonces es muy seguro ignorar el evento, ya que no tiene sentido actuar sobre él.

 @Override public void onItemClick(AdapterView parent, View view, int position, long id) { if (isPaused()) { //But... we're paused. Ignore. return; } //Act upon legitimate click events here } 

Puedo confirmar que se trata de un problema en la biblioteca de soporte y no en el código. La mejor solución es (probablemente) utilizar la respuesta dada por @Doge que es seguir el estado de pausa usted mismo.

La razón por la que es un problema con la biblioteca de soporte es que onClicks ocurre después de un clic de liberación . Si utiliza varios dedos, puede liberar otro evento de clic en otro lugar (como otro botón) que cambie el fragmento. La biblioteca de soporte recibe su evento de clic después de que el fragmento cambia, y no comprueba para confirmar que todavía está en primer plano. Eso significa que usted tiene que comprobarlo usted mismo.

Lo que significa que cualquier llamada a setCurrentTab() o setCurrentTabByTag() debe incluir una comprobación para el estado de pausa si quieren evitar este bloqueo. Por favor, corrija si estoy equivocado.

Puesto que la Actividad se detiene y realmente no hay acción correcta para tomar con la cosa que fue seleccionada, quizás la mejor acción a tomar es coger y comer la IllegalStateException. Deje que la UI haga lo que estaba en el proceso de hacer y deje que la FragmentTransaction caiga en el suelo.

  • Cambiar el título de la barra de acción para cada desplazamiento de pestaña en android
  • Fragment's onDestroyView llamado pero la vista no está siendo destruida
  • Cómo persistir los datos de fragmentos después de las transacciones backstack?
  • ¿Cuál es la manera correcta de tratar con los eventos de Fragmento obsoletos onAttach y onInflate
  • Fragmento: qué devolución de llamada se invocó al pulsar el botón de retroceso y personalizarlo
  • Cómo llamar a fragment method de la actividad principal
  • Cómo obtener datos de DialogFragment a un fragmento?
  • Obtener una referencia a un niño Fragmento después de que el fragmento padre se ha recreado
  • Android: ¿Cómo puedo actualizar mi textView en un fragmento
  • Contenido de la barra ActionBar que se superpone
  • Cómo llamar a fragmento de una actividad en android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.