Android: ¿Cómo reiniciar automáticamente una aplicación después de haber sido "forzada a cerrar"?

81

En una aplicación de Android, normalmente aparece el error "Forzar cierre" si no gestionamos las excepciones correctamente.

¿Cómo puedo reiniciar mi aplicación automáticamente si se cierra a la fuerza?

¿Se utiliza algún permiso específico para esto?

Johnny
fuente
5
Trate de hacer las excepciones correctamente. Una aplicación que se reinicia automáticamente puede resultar molesta para los usuarios.
Tomas Andrle
12
Solo quiero reiniciar mi aplicación si falla. Creo que sería más amigable que molesto, especialmente cuando el usuario está en mi aplicación. Y sí, estoy tratando de hacer bien todas las excepciones. :)
Johnny
2
@Johnny: Comparta la solución para su problema.
Code_Life
Consulte este artículo para reiniciar su aplicación en cualquier excepción.
Chintan Rathod

Respuestas:

100

Para lograr esto tienes que hacer dos cosas:

  1. Evite el "cierre forzado", forma estándar de bloqueo de la aplicación.
  2. Configure un mecanismo de reinicio cuando ocurra el bloqueo de todos modos.

Vea a continuación cómo hacer esto:

  1. Llame Thread.setDefaultUncaughtExceptionHandler()para capturar todas las excepciones no detectadas, en cuyo caso uncaughtException()se llamará al método. "Forzar cierre" no aparecerá y la aplicación dejará de responder, lo cual no es nada bueno. Para reiniciar su aplicación cuando se bloqueó, debe hacer lo siguiente:

  2. En el onCreatemétodo, en su actividad principal, inicialice un PendingIntentmiembro:

    Intent intent = PendingIntent.getActivity(
        YourApplication.getInstance().getBaseContext(),
        0,
        new Intent(getIntent()),
        getIntent().getFlags());
    

Luego ponga lo siguiente en su uncaughtException()método:

AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 2000, intent);
System.exit(2);

También debes llamar System.exit(), de lo contrario no funcionará. De esta forma su aplicación se reiniciará después de 2 segundos.

Eventualmente, puede establecer alguna bandera en su intento de que la aplicación se bloquee y en su onCreate()método puede mostrar un cuadro de diálogo "Lo siento, la aplicación se bloqueó, espero que nunca más :)".

Gyuri Majercsik
fuente
4
Yo deduje eso. ahora el problema es dónde implementar el método uncaughtException ?? por favor ayuda. Gracias.
Jay Mayu
2
@MayuMayooresan Puede extender la clase de aplicación o la Actividad y hacer lo siguiente en onCreate (): Thread.setDefaultUncaughtExceptionHandler (new UncaughtExceptionHandler () {...});
AgentKnopf
1
Si extiende la actividad, vale la pena señalar que debe hacer lo mismo para cada actividad que pueda actuar como un punto de entrada para su aplicación (incluidas aquellas que el sistema operativo Android puede decidir iniciar, por ejemplo, cuando una ventana muere, etc.)
Mick
1
No parece funcionar en ICS después de forzar la detención del proceso a través del menú de administración de aplicaciones.
Sunghun
5
¿Qué significa YourApplication? Usé el consejo de @Mahesh, pero no funcionó. por favor que alguien lo explique.
Shervin Gharib
17

El truco es asegurarse de que no fuerce el cierre en primer lugar.

Si usa el Thread.setDefaultUncaughtExceptionHandler()método , puede detectar las Excepciones que están causando que su aplicación se cierre por la fuerza.

Eche un vistazo a esta pregunta para ver un ejemplo del uso de un UncaughtExceptionHandlerpara registrar las excepciones generadas por una aplicación.

Dave Webb
fuente
1
Gracias por la pista. Una pregunta de seguimiento es ¿cuándo se llamaría a UncaughtExceptionHandler.uncaughtException? Si el usuario no hizo clic en el botón "Forzar cierre", ¿se seguirá llamando a UncaughtExceptionHandler.uncaughtException?
Johnny
3
@Johnny Obtienes un cierre forzado cuando la aplicación genera una excepción que no se maneja. Si usa UncaughtExceptionHandler, su aplicación puede manejar todas sus Excepciones y el usuario nunca verá el cuadro de diálogo Forzar cierre. En otras palabras, se llama a UncaughtExceptionHandler cuando se hubiera mostrado el cuadro de diálogo Forzar cierre. Sin embargo, deberá tener cuidado con la forma en que maneja las Excepciones inesperadas que detecta su aplicación; Seguir adelante y fingir que no pasó nada es obviamente arriesgado.
Dave Webb
Gracias por la explicación. Explica bien sobre UncaughtExceptionHandler. Pero he visto aplicaciones que se reiniciarán automáticamente después del cierre forzado. P.ej. Lanzador (quizás no sea un buen ejemplo, pero he visto que las aplicaciones de terceros también funcionan de esta manera). ¿Qué pasa si quiero que mi aplicación funcione así? ¿Tengo que utilizar algún tipo de permiso del sistema?
Johnny
10

Si usa Crittercism o algún otro servicio de informe de errores, la respuesta aceptada es casi correcta.

final UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            public void uncaughtException(Thread thread, Throwable ex) {
              Intent launchIntent = new Intent(activity().getIntent());
              PendingIntent pending = PendingIntent.getActivity(CSApplication.getContext(), 0,
                    launchIntent, activity().getIntent().getFlags());
              getAlarmManager().set(AlarmManager.RTC, System.currentTimeMillis() + 2000, pending);
              defaultHandler.uncaughtException(thread, ex);
            }
});
Renetik
fuente
2
public class ForceCloseExceptionHandalingActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setContentView(MyLayout());
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                myHandaling(paramThread, paramThrowable);
            }
        });
    }

    private ViewGroup MyLayout(){
        LinearLayout mainLayout = new LinearLayout(this);
        mainLayout.setOrientation(LinearLayout.VERTICAL);  
        Button btnHello =new Button(this);
        btnHello.setText("Show all button");
        btnHello.setOnClickListener(new OnClickListener() {         
            @Override
            public void onClick(View v) {                   
                setContentView(MyLayout2());            
            }
        });             
        mainLayout.addView(btnHello);       
        return mainLayout;
    }

    private ViewGroup MyLayout2(){
        LinearLayout mainLayout = new LinearLayout(this);
        mainLayout.setOrientation(LinearLayout.VERTICAL);  
        Button btnHello =new Button(this);
        btnHello.setText("I am a EEROR uncaughtException");
        btnHello.setOnClickListener(new OnClickListener() {         
            @Override
            public void onClick(View v) {                   
                Log.e("Alert","btn  uncaughtException::");
                Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert uncaughtException222",Toast.LENGTH_LONG).show();
                View buttone = null;
                setContentView(buttone);            
            }
        });     
        Button btnHello2 =new Button(this);
        btnHello2.setText("I am a EEROR Try n catch");
        btnHello2.setOnClickListener(new OnClickListener() {            
            @Override
            public void onClick(View v) {   

                try{
                    View buttone = null;
                    setContentView(buttone);
                }
                catch (Exception e) {
                    Log.e("Alert","Try n catch:::");
                    Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert Try n catch",Toast.LENGTH_LONG).show();
                    setContentView(MyLayout());
                }

            }
        });     
        mainLayout.addView(btnHello);
        mainLayout.addView(btnHello2);
        return mainLayout;
    }
    public void myHandaling(Thread paramThread, Throwable paramThrowable){
        Log.e("Alert","Lets See if it Works !!!" +"paramThread:::" +paramThread +"paramThrowable:::" +paramThrowable);
        Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert uncaughtException111",Toast.LENGTH_LONG).show();
        Intent in =new Intent(ForceCloseExceptionHandalingActivity.this,com.satya.ForceCloseExceptionHandaling.ForceCloseExceptionHandalingActivity.class);
        startActivity(in);
        finish();
        android.os.Process.killProcess(android.os.Process.myPid()); 
    }
    @Override
    protected void onDestroy() {
        Log.e("Alert","onDestroy:::");
        Toast.makeText(ForceCloseExceptionHandalingActivity.this, "Alert onDestroy",Toast.LENGTH_LONG).show();
        super.onDestroy();  
    }
Satya
fuente
este código obtiene el "Thread.setDefaultUncaughtExceptionHandler" y llama después de que se haya cerrado ..
Satya
2

Simplemente agregue esta clase en su paquete

public class MyExceptionHandler implements
    java.lang.Thread.UncaughtExceptionHandler {
private final Context myContext;
private final Class<?> myActivityClass;

public MyExceptionHandler(Context context, Class<?> c) {
    myContext = context;
    myActivityClass = c;
}

public void uncaughtException(Thread thread, Throwable exception) {
    StringWriter stackTrace = new StringWriter();
    exception.printStackTrace(new PrintWriter(stackTrace));
    System.err.println(stackTrace);// You can use LogCat too
    Intent intent = new Intent(myContext, myActivityClass);
    String s = stackTrace.toString();
    //you can use this String to know what caused the exception and in which Activity
    intent.putExtra("uncaughtException", "Exception is: " + stackTrace.toString());
    intent.putExtra("stacktrace", s);
    myContext.startActivity(intent);
    //for restarting the Activity
    Process.killProcess(Process.myPid());
    System.exit(0);
}}

En su aplicación o en cada clase de actividad, dentro del método onCreate (), simplemente llame a:

Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this,
            SplashScreenActivity.class));
Suraj Vaishnav
fuente