[android] Android에서 잡히지 않은 전역 예외 처리기를 설정하는 이상적인 방법

내 Android 애플리케이션의 모든 스레드에 대해 잡히지 않은 전역 예외 처리기를 설정하고 싶습니다. 따라서 내 Application하위 클래스 Thread.UncaughtExceptionHandler에서 포착되지 않은 예외에 대한 기본 처리기로 구현을 설정했습니다 .

Thread.setDefaultUncaughtExceptionHandler(
                new DefaultExceptionHandler(this));

내 구현에서 AlertDialog적절한 예외 메시지 를 표시하려고 합니다.

그러나 이것은 작동하지 않는 것 같습니다. 처리되지 않은 스레드에 대해 예외가 발생할 때마다 재고, OS 기본 대화 상자 ( “Sorry! -Application-has-stopped-unexpectedly dialog”)가 표시됩니다.

포착되지 않은 예외에 대한 기본 처리기를 설정하는 정확하고 이상적인 방법은 무엇입니까?



답변

그게 당신이해야 할 전부입니다. (나중에 프로세스가 중단되도록해야합니다. 상황이 불확실한 상태 일 수 있습니다.)

가장 먼저 확인해야 할 것은 Android 핸들러가 여전히 호출되고 있는지 여부입니다. 버전이 호출되고 있지만 치명적으로 실패하고 system_server가 프로세스 충돌을 볼 때 일반 대화 상자를 표시 할 수 있습니다.

핸들러 상단에 몇 가지 로그 메시지를 추가하여 거기에 도달하는지 확인하십시오. getDefaultUncaughtExceptionHandler의 결과를 인쇄 한 다음 포착되지 않은 예외를 발생시켜 충돌을 유발합니다. 무슨 일이 일어나고 있는지 보려면 logcat 출력을 주시하십시오.


답변

오래 전에 Android 충돌을 사용자 지정 처리하기위한 간단한 솔루션 을 게시했습니다 . 약간 해키하지만 모든 Android 버전 (Lollipop 포함)에서 작동합니다.

먼저 약간의 이론. Android에서 포착되지 않은 예외 처리기를 사용할 때의 주요 문제는 기본 (일명 UI) 스레드에서 발생한 예외와 함께 발생합니다. 그리고 여기에 그 이유가 있습니다. 앱이 시작되면 시스템이 앱 의 Main looper 를 준비하고 시작하는 ActivityThread.main 메서드를 호출 합니다.

public static void main(String[] args) {
  …
  …
    Looper.prepareMainLooper();
  …
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

메인 루퍼는 UI 스레드에 게시 된 메시지 (UI 렌더링 및 상호 작용과 관련된 모든 메시지 포함)를 처리합니다. UI 스레드에서 예외가 발생하면 예외 처리기에 의해 포착되지만 loop()메서드를 벗어 났으므로 UI 메시지를 처리 ​​할 사람이 남아 있지 않으므로 사용자에게 대화 나 활동을 표시 할 수 없습니다. 당신을 위해.

제안 된 솔루션은 매우 간단합니다. Looper.loop자체적으로 메소드를 실행 하고 try-catch 블록으로 둘러 쌉니다. 예외가 발견되면 원하는대로 처리하고 (예 : 사용자 지정 보고서 활동 시작) Looper.loop메서드를 다시 호출 합니다.

다음 메소드는이 기술을 보여줍니다 ( Application.onCreate리스너 에서 호출해야 함 ).

private void startCatcher() {
    UncaughtExceptionHandler systemUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler();

    // the following handler is used to catch exceptions thrown in background threads
    Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler(new Handler()));

    while (true) {
        try {
            Looper.loop();
            Thread.setDefaultUncaughtExceptionHandler(systemUncaughtHandler);
            throw new RuntimeException("Main thread loop unexpectedly exited");
        } catch (Throwable e) {
            showCrashDisplayActivity(e);
        }
    }
}

보시다시피 포착되지 않은 예외 처리기는 백그라운드 스레드에서 발생한 예외에만 사용됩니다. 다음 핸들러는 이러한 예외를 포착하여 UI 스레드로 전파합니다.

static class UncaughtHandler implements UncaughtExceptionHandler {

    private final Handler mHandler;

    UncaughtHandler(Handler handler) {
        mHandler = handler;
    }

    public void uncaughtException(Thread thread, final Throwable e) {
        mHandler.post(new Runnable() {
            public void run() {
                throw new BackgroundException(e);
            }
        });
    }
}

이 기술을 사용하는 예제 프로젝트는 내 GitHub 저장소에서 사용할 수 있습니다. https://github.com/idolon-github/android-crash-catcher


답변

uncaughtException () 메서드에서 previousHandler가 설정된 previousHandler.uncaughtException ()을 호출하지 않는 것을 비활성화한다고 생각합니다.

previousHandler = Thread.getDefaultUncaughtExceptionHandler();


답변

FWIW 나는 이것이 약간 주제에서 벗어난 것을 알고 있지만 우리는 크 리터 시즘의 무료 계획 을 성공적으로 사용하고 있습니다. 또한 앱이 충돌하지 않도록 예외 처리와 같은 몇 가지 프리미엄 기능을 제공합니다.

무료 버전에서는 사용자에게 여전히 충돌이 표시되지만 적어도 이메일과 스택 추적을받습니다.

우리는 또한 iOS 버전을 사용합니다 (하지만 제 동료들로부터 그다지 좋지 않다고 들었습니다).


다음은 비슷한 질문입니다.


답변

전화 할 때까지 작동하지 않습니다.

android.os.Process.killProcess(android.os.Process.myPid());

UncaughtExceptionHandler의 맨 끝에.


답변