En primer lugar, sé que uno no debería realmente matar / reiniciar una aplicación en Android. En mi caso de uso, quiero restablecer de fábrica mi aplicación en un caso específico donde un servidor envía una información específica al cliente.
El usuario solo puede iniciar sesión en el servidor con UNA instancia de la aplicación (es decir, no se permiten varios dispositivos). Si otra instancia obtiene ese bloqueo de "inicio de sesión", todas las demás instancias de ese usuario deben eliminar sus datos (restablecimiento de fábrica) para mantener la coherencia.
Es posible obtener el bloqueo por la fuerza, porque el usuario puede eliminar la aplicación y volver a instalarla, lo que daría como resultado una identificación de instancia diferente y el usuario ya no podrá liberar el bloqueo. Por lo tanto, es posible obtener el bloqueo por la fuerza.
Debido a esa posibilidad de fuerza, debemos verificar siempre en una instancia concreta que tiene el bloqueo. Eso se hace en (casi) cada solicitud al servidor. El servidor puede enviar una "identificación de bloqueo incorrecta". Si se detecta eso, la aplicación cliente debe eliminar todo.
Ese fue el caso de uso.
Tengo una Activity
A que inicia el inicio de sesión Activity
L o la Activity
B principal de la aplicación dependiendo de un valor sharedPrefs. Después de iniciar L o B, se cierra solo para que solo L o B se esté ejecutando. Entonces, en el caso de que el usuario haya iniciado sesión, B ya se está ejecutando.
B comienza C. C llama startService
a la IntentService
D. Eso da como resultado esta pila:
(A)> B> C> D
Desde el método onHandleIntent de D se envía un evento a un ResultReceiver R.
R ahora maneja ese evento al proporcionar al usuario un cuadro de diálogo donde puede elegir restablecer la aplicación de fábrica (eliminar la base de datos, sharedPrefs, etc.)
Después del restablecimiento de fábrica, quiero reiniciar la aplicación (para cerrar todas las actividades) y solo iniciar A nuevamente, que luego inicia el inicio de sesión Activity
L y finaliza:
(A)> L
El método onClick del diálogo se ve así:
@Override
public void onClick(DialogInterface dialog, int which) {
// Will call onCancelListener
MyApplication.factoryReset(); // (Deletes the database, clears sharedPrefs, etc.)
Intent i = new Intent(MyApp.getContext(), A.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApp.getContext().startActivity(i);
}
Y esa es la MyApp
clase:
public class MyApp extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext() {
return context;
}
public static void factoryReset() {
// ...
}
}
El problema es si uso FLAG_ACTIVITY_NEW_TASK
las actividades B y C que aún se están ejecutando. Si presiono el botón Atrás en el inicio de sesión Activity
, veo C, pero quiero volver a la pantalla de inicio.
Si no configuro FLAG_ACTIVITY_NEW_TASK
, aparece el error:
07-07 12:27:12.272: ERROR/AndroidRuntime(9512): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
No puedo usar las Actividades ' Context
, porque la ServiceIntent
D también podría llamarse desde una tarea en segundo plano que es iniciada por AlarmManager
.
Entonces, ¿cómo podría resolver esto con la pila de actividades convirtiéndose en (A)> L?
fuente
Simplemente puede llamar:
Que se usa en la biblioteca ProcessPhoenix
Como alternativa:
Aquí hay una versión un poco mejorada de la respuesta de @Oleg Koshkin.
Si realmente desea reiniciar su actividad, incluida la eliminación del proceso actual, intente con el siguiente código. Colóquelo en una HelperClass o donde lo necesite.
Esto también reinicializará las clases jni y todas las instancias estáticas.
fuente
AlarmManager
y se comportan mal si usan esta solución. ¿Algún mejor enfoque?Jake Wharton publicó recientemente su biblioteca ProcessPhoenix , que hace esto de manera confiable. Básicamente solo tienes que llamar:
La biblioteca finalizará automáticamente la actividad de llamada, cerrará el proceso de la aplicación y luego reiniciará la actividad de la aplicación predeterminada.
fuente
<category android:name="android.intent.category.DEFAULT" />
a su actividad predeterminada <intent-filter> en el manifiesto de la aplicación.He modificado ligeramente la respuesta de Ilya_Gazman para usar nuevas API (IntentCompat está en desuso a partir de la API 26). Runtime.getRuntime (). Exit (0) parece ser mejor que System.exit (0).
fuente
System.exit(n)
es efectivamente equivalente a la llamada:Runtime.getRuntime().exit(n)
". Internamente,System.exit()
solo se da vuelta y llamaRuntime.getRuntime().exit()
. No hay nada "mejor" acerca de uno u otro (a menos que uno esté preocupado por cuánto escribe uno o por una capa adicional de llamadas a métodos).Runtime.getRuntime().exit(0)
(oSystem.exit(0)
) probablemente funcionará. Algunos de mis comentarios "no buenos" son para respuestas (como el de Ilya Gazman que desde entonces ha sido editado para incorporar dicha llamada.)IntentCompat.makeRestartActivityTask
La nueva forma de hacerlo es utilizando IntentCompat.makeRestartActivityTask
fuente
Application
objeto. Por lo tanto, losstatic
datos, los datos inicializados durante la creación de lasApplication
clases jni permanecen en su estado actual y no se reinicializan.IntentCompat.makeRestartActivityTask
ahora está en desuso . Si inspecciona el código fuente , es tan simple como simplemente agregar las banderasIntent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
.Hay un buen truco. Mi problema fue que alguna biblioteca jni de C ++ realmente antigua filtró recursos. En algún momento, dejó de funcionar. El usuario intentó salir de la aplicación y volver a iniciarla, sin ningún resultado, porque terminar una actividad no es lo mismo que terminar (o matar) el proceso. (Por cierto, el usuario podría ir a la lista de aplicaciones en ejecución y detenerla desde allí; esto funcionaría, pero los usuarios simplemente no saben cómo finalizar las aplicaciones).
Si desea observar el efecto de esta función, agregue una
static
variable a su actividad e increméntela, por ejemplo, presionando un botón. Si sale de la actividad de la aplicación y luego vuelve a invocarla, esta variable estática mantendrá su valor. (Si la aplicación realmente se cerró, a la variable se le asignaría el valor inicial).(Y tengo que comentar por qué no quería corregir el error en su lugar. La biblioteca fue escrita hace décadas y filtró recursos desde entonces. La gerencia cree que siempre funcionó . El costo de proporcionar una solución en lugar de una solución ... Creo que entiendes la idea.)
Ahora, ¿cómo podría restablecer una biblioteca compartida jni (también conocida como dinámica, .so) al estado inicial? Elegí reiniciar la aplicación como un nuevo proceso.
El truco es que System.exit () cierra la actividad actual y Android recrea la aplicación con una actividad menos.
Entonces el código es:
La actividad de llamada simplemente ejecuta el código
MagicAppRestart.doRestart(this);
, se ejecuta la actividad de llamadaonPause()
y luego se vuelve a crear el proceso. Y no olvide mencionar esta actividad en AndroidManifest.xmlLa ventaja de este método es que no hay demoras.
UPD: funcionó en Android 2.x, pero en Android 4 algo ha cambiado.
fuente
System.exit(0)
porandroid.os.Process.killProcess(android.os.Process.myPid());
? 2) un bucle infinito probablemente significa que no eliminan la actividad superior cuando reinician una aplicación. En principio, puede agregar una variable booleana estática, establecerla en verdadero antes de invocar la actividad de reinicio, y después del reinicio será falsa. Por lo tanto, la actividad puede averiguar si el reinicio ya ha ocurrido o no (y si ha sucedido, simplemente termine () ). OTOH, su informe significa que el truco no funciona de manera idéntica en todos los dispositivos.Mi solución no reinicia el proceso / aplicación. Solo permite que la aplicación "reinicie" la actividad doméstica (y descarte todas las demás actividades). Parece un reinicio para los usuarios, pero el proceso es el mismo. Creo que en algunos casos la gente quiere lograr este efecto, así que lo dejo aquí para su información.
fuente
Ok, modifiqué mi aplicación y no terminaré A automáticamente. Dejo que esto se ejecute siempre y termine el
onActivityResult
evento. De esta manera puedo usar las banderasFLAG_ACTIVITY_CLEAR_TOP
+FLAG_ACTIVITY_NEW_TASK
para obtener lo que quiero:y en el
ResultReceiver
¡Gracias de cualquier manera!
fuente
fuente
El único código que no activó "Su aplicación se ha cerrado inesperadamente" es el siguiente. También es un código no obsoleto que no requiere una biblioteca externa. Tampoco requiere un temporizador.
fuente
Descubrí que esto funciona en API 29 y versiones posteriores, con el propósito de matar y reiniciar la aplicación como si el usuario la hubiera lanzado cuando no se estaba ejecutando.
Eso se hizo cuando la actividad del iniciador en la aplicación tiene esto:
He visto comentarios que afirman que se necesita una categoría de DEFAULT, pero no he encontrado que ese sea el caso. He confirmado que el objeto Aplicación en mi aplicación se vuelve a crear, por lo que creo que el proceso realmente se ha eliminado y reiniciado.
El único propósito para el que uso esto es reiniciar la aplicación después de que el usuario haya habilitado o deshabilitado los informes de fallas para Firebase Crashlytics. Según sus documentos, la aplicación debe reiniciarse (proceso finalizado y recreado) para que ese cambio surta efecto.
fuente
La mejor manera de reiniciar completamente una aplicación es reiniciarla, no solo saltar a una actividad con
FLAG_ACTIVITY_CLEAR_TOP
yFLAG_ACTIVITY_NEW_TASK
. Entonces, mi solución es hacerlo desde su aplicación o incluso desde otra aplicación, la única condición es conocer el nombre del paquete de la aplicación (ejemplo: ' com.example.myProject ')Ejemplo de reinicio de uso o lanzamiento de la aplicación A desde la aplicación B :
Puede verificar si la aplicación se está ejecutando:
Nota : Sé que esta respuesta está un poco fuera de tema, pero puede ser realmente útil para alguien.
fuente
Mi mejor manera de reiniciar la aplicación es usar
finishAffinity();
Since, solo
finishAffinity();
se puede usar en versiones JELLY BEAN, por lo que podemos usarloActivityCompat.finishAffinity(YourCurrentActivity.this);
para versiones inferiores.Luego, use
Intent
para iniciar la primera actividad, de modo que el código se verá así:Espero eso ayude.
fuente
Intenta usar
FLAG_ACTIVITY_CLEAR_TASK
fuente
Aquí hay un ejemplo para reiniciar su aplicación de manera genérica utilizando PackageManager:
fuente
Application
objeto. Por lo tanto, los datos estáticos, los datos inicializados durante la creación de lasApplication
clases jni permanecen en su estado actual y no se reinicializan.prueba esto:
fuente
Inicie directamente la pantalla inicial con
FLAG_ACTIVITY_CLEAR_TASK
yFLAG_ACTIVITY_NEW_TASK
.fuente
Tuve que agregar un controlador para retrasar la salida:
fuente
Utilizar:
Funciona a partir del nivel de API 16 (4.1), creo.
fuente
Puedes usar el
startInstrumentation
método deActivity
. Necesita implementar vacíoInstrumentation
y puntiagudo en manifiesto. Después de eso, puede llamar a este método para reiniciar su aplicación. Me gusta esto:Obtengo el nombre de la clase Instrumentation dinámicamente pero puedes codificarlo. Algo como esto:
Llame a
startInstrumentation
recargar su aplicación. Lea la descripción de este método. Pero no puede ser seguro si actúa como la aplicación kill.fuente
La aplicación en la que estoy trabajando tiene que dar al usuario la posibilidad de elegir qué fragmentos mostrar (los fragmentos se cambian dinámicamente en tiempo de ejecución). La mejor solución para mí fue reiniciar completamente la aplicación.
Así que probé muchas soluciones y ninguna de ellas me ha funcionado, pero esto:
¡Esperando que eso ayude a alguien más!
fuente
prueba esto:
fuente
Con la biblioteca Process Phoenix . La actividad que desea relanzar se llama "A".
Sabor de Java
Sabor Kotlin
fuente
Puede reiniciar su actividad actual de esta manera:
Fragmento :
Actividad :
fuente