2012-06-27 8 views
13

Nel mio onCreate() ho impostato un gestore UncaughtException come segue:Come ri-generare un'eccezione

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 
    @Override 
    public void uncaughtException(Thread thread, Throwable throwable) { 
     Log.e(getMethodName(2), "uncaughtException", throwable); 
     android.os.Process.killProcess(android.os.Process.myPid()); 
    } 
}); 

funziona bene, ma vorrei tornare comportamento predefinito del sistema di visualizzazione della forza- chiudere la finestra di dialogo per l'utente.

Se provo a sostituire la chiamata KillProcess() con un throw throwable, il compilatore si lamenta che ho bisogno di circondarlo con un try/catch.

Se mi circondano con un try/catch:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 
    @Override 
    public void uncaughtException(Thread thread, Throwable throwable) { 
     try { 
      Log.e(getMethodName(2), "uncaughtException", throwable); 
      throw throwable; 
     } 
     catch (Exception e) {   
     } 
     finally {    
     } 
    } 
}); 

Il compilatore si lamenta ancora che throw throwable bisogno di essere circondati da un try/catch.

Come faccio a ripetere il lancio? Tale che, ad eccezione di quello informativo Log.e(), il sistema si comporta esattamente come prima: come non ho mai impostato un gestore UncaughtException predefinito.

risposta

18

Prova:

public class CustomExceptionHandler implements UncaughtExceptionHandler { 

    private UncaughtExceptionHandler defaultUEH; 

    public CustomExceptionHandler() { 
     this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler(); 
    } 

    public void uncaughtException(Thread t, Throwable e) { 
     Log.e("Tag", "uncaughtException", throwable); 
     defaultUEH.uncaughtException(t, e); 
    } 
} 

e poi Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler());

adattati da this risposta.

+1

Ci scusiamo, ma questo si traduce in un flusso infinito di Eccezioni non rilevate e nessuna finestra di chiusura forzata. Non è quello che sto cercando. –

+0

Ho aggiornato la risposta. – Jeshurun

+0

Funziona alla grande! Accettare +1. –

3

Se si imposta il gestore di eccezioni non rilevate predefinito, è necessario consumare l'eccezione. Ciò si riflette nel fatto che uncaughtException non dichiara alcuna eccezione.

Non ci dovrebbero essere motivi ovvi per rilanciarlo. Verrà semplicemente stampato in log una seconda volta e il thread morirà comunque. Se lo vuoi davvero, basta avvolgere il throwable in RuntimeException e rilanciare.

+0

Capisco e concordo sul fatto che non ci dovrebbero essere ovvi motivi per rilanciarlo.L'unica ragione per cui sto definendo il gestore di default UncaughtException è perché non c'è ** nessun log la prima volta! **. Quindi se il sistema non stampa una traccia dello stack, * I * desidera stamparlo. Da qui il conduttore. Sono stato molto contento del comportamento di default del sistema eccetto per la sua inspiegabile incapacità di stampare una traccia stack di quell'eccezione non rilevata da 'android.net.http.HttpsConnection.openConnection()'. +1. –

+0

Quindi lo hai stampato in gestore. Perché rilanciare? Il thread è già morto ... –

2

Non c'è motivo di rilanciare il Throwable, come per il javadoc, it is simply ignored.. Il thread sta terminando a questo punto, stai solo impostando qual'è l'ultima azione da tentare prima di uscire.

Per amor di discussione, se avete voglia di rigenerare un throwable, si farebbe qualcosa di simile:

public void reThrow(Throwable t) { 
    if (RuntimeException.class.isAssignableFrom(t.getClass())) { 
     throw (RuntimeException)t; 
    } else if (Error.class.isAssignableFrom(t.getClass())) { 
     throw (Error) t; 
    } else { 
     throw new UndeclaredThrowableException(t); 
    } 
} 
+0

+1. Non ho intenzione di provare a lanciare nuovamente perché sono d'accordo con la tua affermazione (vedi [il mio commento] (http://stackoverflow.com/questions/11235513/how-to-re-throw-an-exception#comment14761745_11235599) a @AlexGitelman). Tuttavia, sarebbe bello mostrare all'utente la familiare finestra di chiusura forzata. Qualche idea su come procedere? –

1

prima, non è necessario per rigenerare l'eccezione. uncaughtException() non consuma l'eccezione. devi comunque eseguire la chiamata al metodo del gestore di eccezioni non catturate di default. quindi qualcosa del genere,

class MyUEH implements UncaughtExceptionHandler { 
    private static final UncaughtExceptionHandler default = Thread.getDefaultUncaughtExceptionHandler(); 

    public void uncaughtException(Thread t, Throwable e) { 
     Log.e("Tag", "uncaughtException", throwable); 
     default.uncaughtException(t, e); 
    } 
} 

in secondo luogo, non è necessario uccidere il processo da soli. la UEH predefinita gestirà quella quando ci si chiama.

terzo, l'UEH predefinita mostrerà (o farà sì che venga mostrata) la finestra di dialogo standard di arresto (chiusura forzata) all'utente. tieni presente che se il tuo metodo si blocca (perché stai facendo IO per esempio), allora l'utente non vedrà la finestra di crash fino alla chiusura del tuo metodo.

+0

Amo la tua risposta, ma la realtà è che se commento l'istruzione 'killProcess()' nella prima versione del mio gestore (lasciando solo l'istruzione 'Log.e()', non viene visualizzata alcuna finestra di chiusura forzata la vista dell'applicazione si blocca solo fino a quando non chiudo manualmente l'applicazione. –

+0

sì, hai ragione, ho dimenticato il bocconcino sulla chiamata alla UEH predefinita. –

Problemi correlati