J2ME/SE 에서는 UI Thread (Event Dispatch Thread)가 작업을 처리하다 예외를 만나도
결코 어플리케이션이 죽지 않는다. 데스크탑의 경우 콘솔에 stack trace가 출력되고
해당 이벤트 처리만 안될 뿐이다.
예를 들어 버튼을 눌렀을 때 ActionListener.actionPerformed 에서 divided by zero를 만나면
콘솔에 예외가 출력될 뿐이지 앱이 죽는 경우는 발생하지 않는다.
그러나 Android 플랫폼에서는 UI Thread가 이벤트 핸들러를 실행하다 예외를 만나면
어플리케이션 전체가 주저앉는다. 어찌보면 앱 전체가 죽는 것이 옳다.
예외는 적절히 처리되어야만 하는 녀석이 맞기 때문이다.
안드로이드 기기에는 이러한 예외들을 볼 수 있는 기본 콘솔이 없다.
항상 USB Debugging을 켜두고 있지 않기 때문에 stack trace를 볼 수 있는 방법이 없다.
java.lang.Thread 에 좋은 메서드가 있다. setDefaultUncaughtExceptionHandler 라는 놈이다.
<출처>
http://stackoverflow.com/questions/601503/how-do-i-obtain-crash-data-from-my-android-application
[In a Context (e.g. the main Activity), call]
|
[CustomExceptionHandler.java]
public class CustomExceptionHandler implements UncaughtExceptionHandler { private UncaughtExceptionHandler defaultUEH; private String localPath; private String url;
/* {
public void uncaughtException(Thread t, Throwable e) { String stacktrace = result.toString();
if (localPath != null) {
defaultUEH.uncaughtException(t, e);
private void writeToFile(String stacktrace, String filename) { {
private void sendToServer(String stacktrace, String filename) {
{
|
[upload.php]
|
[index.php]
|
주의할 점은 Thread의 기본 UncaughtException 핸들러를 제거하지 않는 것이다.
앱이 죽는 게 싫다고 새 핸들러에서 예외를 무시해버리면 다음줄에서 예외가 발생하게 되니
점점 더 원인을 찾기 힘들어지기 때문이다.
예외를 만나면 Throwable.getStackTrace()로 StackTraceElement[]를 뽑아 적절히 가공하여
SD Card에 저장하거나 개발자의 서버로 전송한 뒤 기존 UncaughtException 핸들러를 불러
꼭 앱을 ‘죽여’주자.
그런데 한가지 주의 사항이 있다. 예외가 간헐적으로 발생하고, 개발자가 앱을 빈번히 업데이트하는 경우
stacktrace의 결과가 current codebase와 틀려지는 문제가 생겨서 오류가 발생한 정확한 위치를 파악하기
힘들어지는 문제가 생긴다.
하나의 Tip으로 마켓에 릴리즈 할 때마다 git 커밋로그에 릴리즈 버젼넘버를 포함시키고,
force close 로깅할 때 앱의 버전 번호를 함께 넘긴다. 그러면 예전 버전의 앱에서 오류가 보고 되었을 때도
혼란에 빠지지 않을 수 있다.
stack trace를 네트워크로 전송하고자 한다면 App 내에 android.permission.INTERNET 권한 추가는
필수 !!
요즘 앱을 보면 앱실행중 Exception이 발생하면 앱이 종료 되었다가 재 실행 되는것을 볼 수 있다.
어떻게 앱이 비정상 종료되는 순간을 Catch한것일까?
방법은 UncaughtExceptionHandler를 이용하면 된다.
보통 Thread는 try{} catch(Exception e){}외에 발생 하는 예외는 UncaughtExceptionHandler의 uncaughtThread(Thead thread, Throwable ex)를 호출 하게 되어 있다.
그래서 Thread의 UncaughtExceptionHandler 인스턴스를 Thread에 등록하면 되는데,
Thread의 static메소드인 setDefaultUncaughtExceptionHandler()를 이용하여
UncaughtExceptionHandler를 set할 수 있다.
이렇게 하면 별도로 예외처리 하지 않은 부분에서 예외가 발생 하게되면 uncaughtThread(Thead thread, Throwable ex)가 호출되어 유용한 작업들을 할 수있다.
그럼 간략하게 구현 해보자.
java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.Thread.UncaughtExceptionHandler; import android.app.Application; import android.util.Log; public class MyApplication extends Application { private UncaughtExceptionHandler mUncaughtExceptionHandler; @Override public void onCreate(){ mUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler( new UncaughtExceptionHandlerApplication()); super .onCreate(); } /** * 메시지로 변환 * @param th * @return */ private String getStackTrace(Throwable th) { final Writer result = new StringWriter(); final PrintWriter printWriter = new PrintWriter(result); Throwable cause = th; while (cause != null ) { cause.printStackTrace(printWriter); cause = cause.getCause(); } final String stacktraceAsString = result.toString(); printWriter.close(); return stacktraceAsString; } class UncaughtExceptionHandlerApplication implements Thread.UncaughtExceptionHandler{ @Override public void uncaughtException(Thread thread, Throwable ex) { //예외상황이 발행 되는 경우 작업 Log.e( "Error" , getStackTrace(ex)); //예외처리를 하지 않고 DefaultUncaughtException으로 넘긴다. mUncaughtExceptionHandler.uncaughtException(thread, ex); } } } |
안드로이드에서 Application onCreate()에서 Thread.setDefaultUncaughtExceptionHandler를
구현해주면 끝이다.
예외 상황 발생시 AlarmManager로 앱을 재 실행 하던가, 로그를 저장해두었다가 앱이 재 실행 되면
서버로 전송하는 기능을 구현하면 될 듯 하다.
실제로 ACRA이라는 버그리포팅 해주는 라이브러리가 이런 방법으로 구현 되어 있다.
레퍼런스도 참고 하기 바란다.
http://developer.android.com/reference/java/lang/Thread.UncaughtExceptionHandler.html
'IT_Programming > Android_Java' 카테고리의 다른 글
Android(Java) httpClient + zlib(zip) (0) | 2011.11.27 |
---|---|
Android Java Package 지원범위 (0) | 2011.11.26 |
갤럭시 시리즈 MyLocationOverlay가 오류가 날 때 ! (0) | 2011.11.10 |
[펌_번역] 안드로이드 메모리릭 회피하기 (0) | 2011.10.31 |
[펌] 안드로이드 원격 디버깅 환경 구성하기(Android Remote Debugging) (0) | 2011.10.17 |