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:
- El ERROR sobre DrawerLayout (IllegalArgumentException: Ver android.widget.RelativeLayout no es un cajón deslizante)
- Cuando isValidFragment () de android de PreferenceActivity se llama?
- cómo obtener Resultado de onActivityResult en Fragment?
- Evitar Android volver a agregar automáticamente mi fragmento en el cambio de orientación
- Inter fragmento de comunicación utilizando rxjava
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 yOnItemClickListener
s enonSaveInstanceState
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()
yonRestoreInstanceState()
y comprobar que en onClick (), pero de nuevo, eso es sólo un kludge. EDIT: Oh, el fragmento no tieneonRestoreInstanceState()
, pero puedo girar la bandera enonResume()
o lo que sea.
¿Hay una solución correcta para esto que me falta, o debería ir con mi kludge de elección?
- ViewPager - onCreateView no siempre se llama
- Android DialogFragment desaparece después del cambio de orientación
- Toast dentro del método onClick en Fragment
- Excepción AlertDialog de Android "Resources $ NotFoundException"
- ¿Cómo hacer estallar detrás la pila para la actividad con los fragmentos múltiples?
- Pasar datos entre Fragmentos anidados
- Java.lang.IllegalStateException: No se puede realizar esta acción después de onSaveInstanceState: - Error en Fragment
- Sincronizar todo el ListView en un ViewPager
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.