인문주의 사피엔스

Flutter에서 일괄적으로 오류를 잡는 방법 본문

프로그래밍/Flutter

Flutter에서 일괄적으로 오류를 잡는 방법

인문주 2022. 4. 16. 15:44
반응형

Flutter에서 실행 오류를 감지하기 위해서 사용하는 대표적인 방법으로 try catch가 있습니다. 그러나 try catch는 프로그래머가 관심을 두는 특정 위치에서 발생하는 오류를 잡을 때는 유용하지만, 불특정 위치에서 발생하는 오류를 잡는 목적으로는 적당하지 않습니다. 왜냐하면 불특정한 위치는 ‘모든’ 위치를 의미하기 때문입니다. 소스코드의 모든 위치에 try catch를 넣는 것은 불필요할 뿐만 아니라 불가능에 가까운 일이라고 할 수 있습니다. Flutter는 그런 불특정 오류를 다루기 위한 별도의 방법들을 제공하고 있습니다. 그 방법들은 오류의 특성에 따라 아래와 같이 세 가지 종류로 분류할 수 있습니다. 

 

1. Flutter 내부에서 오류가 발생하는 경우

다음 코드는 버튼이 눌려졌을 때 오류를 발생시킵니다.

 

OutlinedButton(
  child: const Text('1. error inside Flutter'),
  onPressed: () {
    makeError();
  },
),

void makeError() {
  final list = ['a'];
  for (var n = 0; n < list.length + 1; n++) {
    log(list[n]);
  }
}

 

위와 같은 경우에 makeError를 try catch로 감싸는 대신 다음과 같이 runApp을 호출하기 전에 FlutterError.onError를 설정하는 방법을 사용할 수 있습니다.

 

void main() {
  FlutterError.onError = (details) {
    FlutterError.presentError(details);
  };
  runApp(const MyApp());
}

 

FlutterError.onError를 사용하면 Flutter 프레임워크 내부에서 발생하는 모든 오류를 감지할 수 있습니다.

 

2. 위젯 생성 과정에서 오류가 발생하는 경우

다음과 같이 MaterialApp.builder에서 ErrorWidget.builder를 설정하면 위젯의 build 함수에서 오류가 발생하는 경우에 화면을 사용자 정의 오류 위젯으로 대체할 수도 있습니다.

 

return MaterialApp(
  builder: (context, widget) {
    ErrorWidget.builder = (errorDetails) {
      Widget error = Text('$errorDetails');
      if (widget is Scaffold || widget is Navigator) {
        error = Scaffold(body: SafeArea(child: error));
      }
      return error;
    };
    return widget!;
  },
  home: const MyHome(),
);

 

3. Flutter 외부에서 오류가 발생하는 경우

Android나 iOS 등의 플랫폼 별 코드의 실행을 위한 플러그인이나 또는 pub.dev에서 내려 받은 패키지를 사용할 때처럼 Flutter 프레임워크의 외부에서 오류가 발생하는 경우가 있습니다. 다음 코드는 버튼이 눌러졌을 때 존재하지 않는 플러그인을 호출하여 오류를 발생시킵니다.

 

OutlinedButton(
  child: const Text('1. error outside Flutter'),
  onPressed: () async {
    const channel = MethodChannel('fake-channel');
    await channel.invokeMethod('blah');
  },
),

 

위와 같은 경우에 대해 try catch를 개별적으로 사용할 수도 있지만, 대신 아래와 같이 runApp을 runZonedGuarded 함수로 둘러싸서 모든 오류를 일괄적으로 감지할 수 있습니다.

 

void main() {
  runZonedGuarded(() {
    runApp(const MyApp());
  }, (error, stackTrace) {
    log('error outside Flutter', error: error, stackTrace: stackTrace);
  });
}

 

다음은 전체 소스코드입니다.

 

 

반응형
Comments