본문 바로가기

Flutter

플러터(Flutter) - 외부 데이터 불러올때 try / catch 오류(error) 처리

반응형

 

외부에서 Json이나 csv 파일을 비동기로 불러올 때 일반적으로 발생할 수 있는 에러들의 처리 방법입니다.

 

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class Test extends StatefulWidget {
  const Test({Key? key}) : super(key: key);

  @override
  State<Test> createState() => _TestState();
}

class _TestState extends State<Test> {
  @override
  void initState() {
    super.initState();
    try {
      // 데이터 불러오기
      // http.Response response = await http.get(site);
    } on SocketException {
      // 인터넷 연결 확인
      failure('인터넷 연결을 할 수 없습니다.', false);
    } on FormatException {
      // 지정된 데이터 형식이 없거나 다른경우
      failure('데이터를 읽어 오지 못했습니다.', false);
    } on HttpException {
      // 인터넷 페이지를 못 찾았을 때
      failure('지정된 페이지를 찾을 수 없습니다.', false);
    } catch (e) {
      failure(e.toString(), false);
    }
  }

  void failure(String message, bool isCheck) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      showDialog(
          context: context,
          barrierDismissible: false,
          builder: (builder) {
            return AlertDialog(
              title: const Text('오류'),
              content: Text(message),
              actions: [
                isCheck
                    ? ElevatedButton(
                        onPressed: () => SystemNavigator.pop(),
                        child: const Text(
                          '종료',
                          style: TextStyle(fontSize: 18, color: Color.fromARGB(255, 237, 231, 255)),
                        ),
                      )
                    : ElevatedButton(
                        onPressed: () {
                          // 확인 버튼 처리
                        },
                        child: const Text(
                          '확인',
                          style: TextStyle(fontSize: 16, color: Color.fromARGB(255, 237, 231, 255)),
                        ),
                      ),
              ],
            );
          });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Text('Test'),
    );
  }
}

 

@override
  void initState() {
    super.initState();
    try {
      // 데이터 불러오기
      // http.Response response = await http.get(site);
    } on SocketException {
      // 인터넷 연결 확인
      failure('인터넷 연결을 할 수 없습니다.', false);
    } on FormatException {
      // 지정된 데이터 형식이 없거나 다른경우
      failure('데이터를 읽어 오지 못했습니다.', false);
    } on HttpException {
      // 인터넷 페이지를 못 찾았을 때
      failure('지정된 페이지를 찾을 수 없습니다.', false);
    } catch (e) {
      failure(e.toString(), false);
    }
  }

initState에서 외부에서 비동기로 데이터를 불러올 때 try / catch를 사용합니다.

이때 여러 오류들 중 가장 일반적인 에러들을 간단히 처리해주는 명령어들이 dart:io에 포함되어 있습니다.

 

on SocketException {
      // 인터넷 연결 확인
      failure('인터넷 연결을 할 수 없습니다.', false);
}

인터넷 연결에 문제가 있다면 처리할 수 있는 부분입니다.

 

on FormatException {
      // 지정된 데이터 형식이 없거나 다른경우
      failure('데이터를 읽어 오지 못했습니다.', false);
}

가져오고자 하는 데이터와 받는 곳의 데이터형식이 다르거나 없을 경우에 처리 하는 부분 입니다.

 

on HttpException {
      // 인터넷 페이지를 못 찾았을 때
      failure('지정된 페이지를 찾을 수 없습니다.', false);
}

지정된 페이지의 주소가 맞지 않을 경우 HttpException에서 처리하게 됩니다.

 

catch (e) {
      failure(e.toString(), false);
}

마지막으로 기타 오류를 처리하게 됩니다.

 

그리고 failure 함수는 이런 에러 메시지를 Dialog를 통해 화면에 표시해 줍니다.

문제는 일반적인 방법으론  initState 안에선 위젯을 표시할 수 없지만 

WidgetsBinding.instance.addPostFrameCallback 을 통해 사용할 수 있습니다.

 

void failure(String message, bool isCheck) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      showDialog(
          context: context,
          barrierDismissible: false,
          builder: (builder) {
            return AlertDialog(
              title: const Text('오류'),
              content: Text(message),
              actions: [
                isCheck
                    ? ElevatedButton(
                        onPressed: () => SystemNavigator.pop(),
                        child: const Text(
                          '종료',
                          style: TextStyle(fontSize: 18, color: Color.fromARGB(255, 237, 231, 255)),
                        ),
                      )
                    : ElevatedButton(
                        onPressed: () {
                          // 확인 버튼 처리
                        },
                        child: const Text(
                          '확인',
                          style: TextStyle(fontSize: 16, color: Color.fromARGB(255, 237, 231, 255)),
                        ),
                      ),
              ],
            );
          });
    });
  }

String message와 bool isCheck를 받으며 message는 오류 메시지를 isCheck는 앱 시작 부분에서 문제가 생길 경우 오류 메시지를 표시함과 동시에 앱을 종료시킬 때 또는 일반 에러 메시지의 표시를 구분하기 위한 것입니다.

현재 위 코드는 한 라인에서 적용했기에 context를 바로 받았지만 failure을 별도로 지정한다면 BuildContext를 받아 오시면 됩니다.

아니면 GetX를 사용하시면 context 없이 사용하실 수 있습니다.

 

WidgetsBinding.instance.addPostFrameCallback((_) {
	// 화면 표시 위젯
});

만약 이 부분에 문제가 생긴다면 아래 코드로 사용해 보시기 바랍니다.

 

 T? _ambiguate<T>(T? value) => value;

  _ambiguate(WidgetsBinding.instance)!.addPostFrameCallback((_) {
	// 화면 표시 위젯
  });
반응형