Tengo el siguiente código en mi onActivityResult para un fragmento mío:
onActivityResult(int requestCode, int resultCode, Intent data){
//other code
ProgressFragment progFragment = new ProgressFragment();
progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG);
// other code
}
Sin embargo, recibo el siguiente error:
Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
¿Alguien sabe qué está pasando o cómo puedo solucionarlo? Debo tener en cuenta que estoy usando el paquete de soporte de Android.
android
android-fragments
android-dialogfragment
Kurtis Nusbaum
fuente
fuente
onResumeFragments()
no existe en laActivity
clase. Si está utilizando un básicoActivity
, debería utilizaronPostResume()
en su lugar.EDITAR: No es un error, sino más bien una deficiencia en el marco de fragmentos. La mejor respuesta a esta pregunta es la proporcionada por @Arcao arriba.
---- Publicación original ----
En realidad, es un error conocido con el paquete de soporte (editar: en realidad no es un error. Ver el comentario de @ alex-lockwood). Una solución alternativa publicada en los comentarios del informe de error es modificar la fuente del DialogFragment de esta manera:
public int show(FragmentTransaction transaction, String tag) { return show(transaction, tag, false); } public int show(FragmentTransaction transaction, String tag, boolean allowStateLoss) { transaction.add(this, tag); mRemoved = false; mBackStackId = allowStateLoss ? transaction.commitAllowingStateLoss() : transaction.commit(); return mBackStackId; }
Tenga en cuenta que este es un truco gigante. La forma en que realmente lo hice fue crear mi propio fragmento de diálogo con el que pudiera registrarme desde el fragmento original. Cuando ese otro fragmento de diálogo hizo cosas (como ser descartado), le dijo a los oyentes que se iba. Lo hice así:
public static class PlayerPasswordFragment extends DialogFragment{ Player toJoin; EditText passwordEdit; Button okButton; PlayerListFragment playerListFragment = null; public void onCreate(Bundle icicle){ super.onCreate(icicle); toJoin = Player.unbundle(getArguments()); Log.d(TAG, "Player id in PasswordFragment: " + toJoin.getId()); } public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle){ View v = inflater.inflate(R.layout.player_password, container, false); passwordEdit = (EditText)v.findViewById(R.id.player_password_edit); okButton = (Button)v.findViewById(R.id.ok_button); okButton.setOnClickListener(new View.OnClickListener(){ public void onClick(View v){ passwordEntered(); } }); getDialog().setTitle(R.string.password_required); return v; } public void passwordEntered(){ //TODO handle if they didn't type anything in playerListFragment.joinPlayer(toJoin, passwordEdit.getText().toString()); dismiss(); } public void registerPasswordEnteredListener(PlayerListFragment playerListFragment){ this.playerListFragment = playerListFragment; } public void unregisterPasswordEnteredListener(){ this.playerListFragment = null; } }
Así que ahora tengo una forma de notificar al PlayerListFragment cuando suceden cosas. Tenga en cuenta que es muy importante que llame a unregisterPasswordEnteredListener de manera adecuada (en el caso anterior, cuando el PlayerListFragment "desaparece"), de lo contrario, este fragmento de diálogo podría intentar llamar a funciones en el oyente registrado cuando ese oyente ya no existe.
fuente
show()
y capture elIllegalStateException
.onActivityResult()
! Pruebe esta solución en su lugar: stackoverflow.com/questions/16265733/…onPostResume
yonResumeFragments
ambas son adiciones relativamente nuevas a la biblioteca de soporte.El comentario dejado por @Natix es un breve resumen que algunas personas pueden haber eliminado.
La solución más simple a este problema es llamar a super.onActivityResult () ANTES de ejecutar su propio código. Esto funciona independientemente de si está utilizando la biblioteca de soporte o no y mantiene la coherencia de comportamiento en su Actividad.
Ahi esta:
Cuanto más leo sobre esto, más trucos locos he visto.
Si todavía tiene problemas, entonces el de Alex Lockwood es el que debe verificar.
fuente
super.onActivityResult(requestCode, resultCode, data)
antes de cualquiera de mi código, solucionó mi problema. Pero al agregar herencia o anular el onActivityResult predeterminado, debemos manejar el onStart / onResume manualmenteCreo que es un error de Android. Básicamente, Android llama a onActivityResult en un punto incorrecto del ciclo de vida de la actividad / fragmento (antes de onStart ()).
El error se informa en https://issuetracker.google.com/issues/36929762
Lo resolví básicamente almacenando el Intent como un parámetro que luego procesé en onResume ().
[EDITAR] En la actualidad, existen mejores soluciones para este problema que no estaban disponibles en 2012. Vea las otras respuestas.
fuente
onActivityResult()
se llama antesonResume()
EDIT: Sin embargo, otra opción, y, posiblemente, el mejor hasta ahora (o, al menos lo que el apoyo Espera biblioteca ...)
Si está usando DialogFragments con la biblioteca de soporte de Android, debería usar una subclase de FragmentActivity. Intente lo siguiente:
onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, intent); //other code ProgressFragment progFragment = new ProgressFragment(); progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG); // other code }
Eché un vistazo a la fuente de FragmentActivity, y parece que está llamando a un administrador de fragmentos interno para reanudar los fragmentos sin perder el estado.
Encontré una solución que no figura aquí. Creo un controlador e inicio el fragmento de diálogo en el controlador. Entonces, editando tu código un poco:
onActivityResult(int requestCode, int resultCode, Intent data) { //other code final FragmentManager manager = getActivity().getSupportFragmentManager(); Handler handler = new Handler(); handler.post(new Runnable() { public void run() { ProgressFragment progFragment = new ProgressFragment(); progFragment.show(manager, PROG_DIALOG_TAG); } }); // other code }
Esto me parece más limpio y menos malicioso.
fuente
Thread#sleep()
.super.onActivityResult()
es la solución de trabajo más simple que existe y probablemente debería ser la respuesta aceptada. Noté que faltaba la súper llamada por accidente y me sorprendió gratamente que agregarla simplemente funcionó. Esto me permitió eliminar uno de los antiguos trucos mencionados en esta página (guardar el cuadro de diálogo en una variable temporal y mostrarloonResume()
).onActivityResult()
no devuelve ningún valor que indique si los fragmentos manejaron o no el resultado.Hay dos métodos show () de DialogFragment -
show(FragmentManager manager, String tag)
yshow(FragmentTransaction transaction, String tag)
.Si desea usar la versión FragmentManager del método (como en la pregunta original), una solución fácil es anular este método y usar commitAllowingStateLoss:
public class MyDialogFragment extends DialogFragment { @Override public void show(FragmentManager manager, String tag) { FragmentTransaction ft = manager.beginTransaction(); ft.add(this, tag); ft.commitAllowingStateLoss(); } }
Primordial
show(FragmentTransaction, String)
esta forma no es tan fácil porque también debería modificar algunas variables internas dentro del código DialogFragment original, por lo que no lo recomendaría; si desea usar ese método, pruebe las sugerencias en la respuesta aceptada (o el comentario de Jeffrey Blattman).Existe cierto riesgo al usar commitAllowingStateLoss - la documentación dice "Como commit () pero permite que el commit se ejecute después de que se guarda el estado de una actividad. Esto es peligroso porque el commit se puede perder si la actividad necesita ser restaurada posteriormente desde su estado , por lo que esto solo debe usarse en los casos en que está bien que el estado de la interfaz de usuario cambie inesperadamente en el usuario ".
fuente
No puede mostrar el diálogo después de la actividad adjunta llamada su método onSaveInstanceState (). Obviamente, onSaveInstanceState () se llama antes de onActivityResult (). Por lo tanto, debe mostrar su diálogo en este método de devolución de llamada OnResumeFragment (), no necesita anular el método show () de DialogFragment. Espero que esto te ayudará.
fuente
Se me ocurrió una tercera solución, basada parcialmente en la solución de hmt. Básicamente, cree una ArrayList de DialogFragments, que se mostrará en onResume ();
ArrayList<DialogFragment> dialogList=new ArrayList<DialogFragment>(); //Some function, like onActivityResults { DialogFragment dialog=new DialogFragment(); dialogList.add(dialog); } protected void onResume() { super.onResume(); while (!dialogList.isEmpty()) dialogList.remove(0).show(getSupportFragmentManager(),"someDialog"); }
fuente
onActivityResult () se ejecuta antes que onResume (). Necesita hacer su IU en onResume () o posterior.
Utilice un booleano o lo que necesite para comunicar que se ha obtenido un resultado entre ambos métodos.
... Eso es. Sencillo.
fuente
Sé que esto fue respondido hace bastante tiempo ... pero hay una manera mucho más fácil de hacer esto que algunas de las otras respuestas que vi aquí ... En mi caso específico, necesitaba mostrar un DialogFragment de un fragmento onActivityResult () método.
Este es mi código para manejar eso, y funciona muy bien:
DialogFragment myFrag; //Don't forget to instantiate this FragmentTransaction trans = getActivity().getSupportFragmentManager().beginTransaction(); trans.add(myFrag, "MyDialogFragmentTag"); trans.commitAllowingStateLoss();
Como se mencionó en algunas de las otras publicaciones, comprometerse con la pérdida de estado puede causar problemas si no tiene cuidado ... en mi caso, simplemente estaba mostrando un mensaje de error al usuario con un botón para cerrar el cuadro de diálogo, así que si el estado de que está perdido no es gran cosa.
Espero que esto ayude...
fuente
Es una vieja pregunta pero la he resuelto de la manera más sencilla, creo:
getActivity().runOnUiThread(new Runnable() { @Override public void run() { MsgUtils.toast(getString(R.string.msg_img_saved), getActivity().getApplicationContext()); } });
fuente
Sucede porque cuando se llama a #onActivityResult (), la actividad principal ya ha llamado a #onSaveInstanceState ()
Usaría un Runnable para "guardar" la acción (mostrar diálogo) en #onActivityResult () para usarlo más tarde cuando la actividad esté lista.
Con este enfoque nos aseguramos de que la acción que queremos siempre funcione
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == YOUR_REQUEST_CODE) { mRunnable = new Runnable() { @Override public void run() { showDialog(); } }; } else { super.onActivityResult(requestCode, resultCode, data); } } @Override public void onStart() { super.onStart(); if (mRunnable != null) { mRunnable.run(); mRunnable = null; } }
fuente
La solución más limpia que encontré es esta:
@Override public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { new Handler().post(new Runnable() { @Override public void run() { onActivityResultDelayed(requestCode, resultCode, data); } }); } public void onActivityResultDelayed(int requestCode, int resultCode, Intent data) { // Move your onActivityResult() code here. }
fuente
Recibí este error mientras estaba
.show(getSupportFragmentManager(), "MyDialog");
en actividad.Intente
.show(getSupportFragmentManager().beginTransaction(), "MyDialog");
primero.Si aún no funciona, esta publicación ( Show DialogFragment from onActivityResult ) me ayuda a resolver el problema.
fuente
De otra manera:
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case Activity.RESULT_OK: new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message m) { showErrorDialog(msg); return false; } }).sendEmptyMessage(0); break; default: super.onActivityResult(requestCode, resultCode, data); } } private void showErrorDialog(String msg) { // build and show dialog here }
fuente
solo llama
super.onActivityResult(requestCode, resultCode, data);
antes de manejar el fragmentofuente
Como todos saben, este problema se debe a que onActivityResult () está llamando antes de onstart (), así que simplemente llame a onstart () al inicio en onActivityResult () como lo he hecho en este código
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { onStart(); //write you code here }
fuente