오류처리 및 예외처리란 무엇인가?
시스템 레벨(error)이든 어플리케이션 레벨(exception)이든 원하는 의도대로 프로그램이 작동되지 않는 모든 경우를 오류 혹은 예외라 한다. 오류없는 코드란 절대 불가능하기때문에 오류가 발행할 것을 대비하여 잘 처리해줘야한다. 특히 예외는 개발자가 처리할 수 있기때문에 예외를 구분하고 그에 따른 적절한 처리방법을 명확히 알고 적용해야한다.
오류와 예외는 모두 Throwable 클래스를 상속받고 있고 java에서 throw를 통해 발생시킬 수 있다.
오류/예외는 크게 3가지가 있다.
참고: throws vs throw ?
-> https://jade314.tistory.com/entry/%EC%97%90%EB%9F%AC-%EB%8D%98%EC%A7%80%EA%B8%B0-throw-vs-throws
Error
- 시스템 레벨에서 발생
java.lang.Error 클래스의 서브 클래스들
오류는 시스템에서 비정상적 상황이 발생했을때 발생한다. 예를들어 메모리가 부족한다든가(OutOfMemoryError), (존재하지 않는 파일을 열때) IOError 등 개발자가 미리 상황을 예측하여 처리할수 없는 시스템 레벨에서 발생하는 오류이다. 따라서 애플리케이션에서는 이러한 오류에 대한 처리는 신경쓰지 않아도(어짜피 못하니까) 된다.
기기의 메모리 사이즈를 크게하거나 하는등의 시스템에 변화를 주어야 처리가 가능하다.
Exception
- 개발자가 구현한 로직에서 발생
java.lang.Exception 클래스와 그 서브클래스들
예외는 개발가 로직을 추가하여 처리할 수 있다. Exception 클래스의 자삭클래스는 또
Checked Exception(체크 예외) = compile time Exception 와
Unchecked Exception(언체크 예외) = Runtime Exception
로 구분할 수 있다.
두 분류를 나누는 큰 기준은 "꼭 처리"해야하는가 이다. Checked Exception 인 경우 try catch 로 감싸지 않으면 코드에 붉은색 줄로 표시가 된다. 반면 Checked Exception(RuntimeException)인경우 명시적인 예외처리는 하지 않아도 되지만 개발자의 부주의에 의해 발행하는경우가 대부분이고, 미리 예측하지 못한 상황에서 발생하는예외가 아니라 처리할 필요가 없도록 만들어졌다.
예외 처리를 하는 목적은 무엇인가?
첫째, 사용자에게 오류 발생을 알려야 한다.
- 사용자에게 이때 알릴 내용은 개발자가 알아야할 내용과는 다르다 자세히 왜 오류가 발생했는지 알려줘봤자 혼돈만 오고 서비스에 대한 신뢰만 떨어질 뿐이다.
- 사용자에게 오류 발생을 알리는 목표는 오류 발생 시 사용자가 대처할 수 있게 하여 이탈을 방지함에 있다.
- 오류 발행 이후 행동 정의
- 오류가 발생했음을 알리는 다이얼로그 화면 띄움 (이 부분은 상황에 따라 생략가능)
- 이전에 열려있었던 화면(혹은 의도된 특정 화면)을 자동으로 다시 실행 혹은 앱 종료 후 자동으로 다시 실행
둘째, 오류가 발생했음을 개발자가 알 수 있도록 해야한다.
- 이유는 오류가 왜 어디에서 발생했는지 알아야지 없앨 수 있는 오류를 수정할 수 있게 된다. (목표: 오류개선)
- 따라서 어떤상황에서 언제 발생했는지에 대한 내용이 자세할수록 좋다.
- 이런 오류 발생에 대한 로그들을 관리해주는 기능의 대표적인 서비스가 바로 Firebase Crashlyrics다.
그렇다면 정확히 어떤 처리를 해야하는가?
개발자가 예외를 만나면 할 수 있는 처리가 크게 다음과 같이 3가지가 있다.
1. 예외 복구(다른 작업 흐르으로 유도)
2. 예외처리 회피(처리하지 않고 호출한 쪽으로 throws, catch)
3. 예외 전환 (명확한 의미의 예외로 전환 후 throw)
각 방법 예시 코드 및 설명-> withseungryu.tistory.com/94?category=753128
그러나
한번에 위 3가지의 예외처리가 되어있으면 좋겠지만, 현실에서는 모든 예외의 경우의 수를 다 보지 못한다.모든 에러를 다 잡지 못하고 앱을 배포하게 될 수 밖에 없다.
하지만 적어도 에러처리의 2가지 목표(첫째, 사용자에게 알리고 적절한 처리, 둘째, 오류가 발생했음을 개발자가 알아야함) 두가지를 만족시켜야한다.
첫째, 사용자측면에서 처리를 위해서는 발생할수 있는 예외들을 한번에 묶어서 처리(CaughtException /UncaughtException)하게 한다.
먼저 예외가 발생할 수 있는 부분들을 throws 를 통해 상위 블럭으로 던저주고 (Caught된 exception)
사용자에게 에러가 발행했음을 띄어주고 앱을 재실행 시켜준다. → CaughtException
그러나 모든 코드를 try catch 로 감싸며 예외를 고려할 수는 없는데 이때 사용되는 기능이 Thread 클래스의 UncaughtExceptionHandler 클래스를 사용하면 된다. → UncaughtException
두 경우의 예외가 발생하면 앱을 재실행시켜주어 사용자측면의 사용성을 유지할 수 있다.
둘째, 발생한 예외들의 로그를 쌓아두며(firebase crashlytics) 하나씩 개선해 나가야 한다.
파이어베이스에서 제공하고 있는 crashlytics(연동방법 참고: firebase.google.com/docs/crashlytics)를 연동하면 예외가 발생할때마다 다음과 같이 로그를 자동으로 쌓을 수 있다.
하지만 이때 crashlytics 기본 연동으로 날라오는 로그는 UncaughtExceptionHandler 로 잡힌 예외만 날라오게된다.
나의 경우, throws 로 상단으로 던져준 에러들도 보고싶어 최종 상단에 다음과 같은 별도의 코드를 작성하였다.
이렇게 코드를 작성하면 에러 발생시
1. firebase 콘솔에서 아래와같이 분류하여 확인할 수 있고
2. CaughtExceptionActivity에 구현한데로 오류 발생했음을 다이얼로그창으로 띄울 수 있다.
참고
'Android > Android 기본기' 카테고리의 다른 글
Android Thread (UI Thread로 전환) (0) | 2021.04.22 |
---|---|
에러 던지기 throw vs throws (0) | 2021.04.05 |
3. 안드로아드 아키텍처와 앱 실행원리 (0) | 2013.05.07 |
2. 프로젝트 개발과 실행원리 (0) | 2013.05.07 |
1. 안드로이드 개발환경 설치 (0) | 2013.05.07 |