📌 Day 2: Dart & Flutter 기초부터 실전까지! 비동기 프로그래밍 (async/await, Future)

2025. 2. 20. 07:43같이 공부합시다 - Flutter/Dart & Flutter 기초부터 실전까지

728x90


📌 주제

Dart의 비동기 프로그래밍 이해하기
Future, async/await 활용법
Flutter에서 API 데이터를 비동기로 가져오는 방법
 
 
 


1️⃣ 비동기 프로그래밍 개념

📌 비동기(Asynchronous)란?

  • 동기 : 일반적인 코드 실행 흐름
  • 비동기 : 시간이 오래 걸리는 작업, 블로킹(blocking) 없이 실행하는 방식.
  • 예시) 네트워크 요청(API 호출), 파일 읽기, 데이터베이스 쿼리, 타이머 등

 
📌 Dart에서 비동기 작업을 처리하는 방법
 
1️⃣ Future (미래의 값, 비동기 작업 결과)
2️⃣ async / await (비동기 코드를 동기적으로 작성할 수 있도록 도와줌)
3️⃣ Stream (연속적인 데이터 흐름을 처리, 예: 실시간 채팅, 센서 데이터)
 
 
 


2️⃣ Future 기본 개념

📌 Future는 "미래에 완료될 값"을 나타내는 객체

  • Future는 즉시 실행되지만, 결과를 받기까지 시간이 걸림.
  • then(), catchError(), whenComplete()를 활용하여 결과 처리 가능.

 

🔹 Future 예제 1: 3초 후에 데이터 반환

Future<String> fetchData() {
  return Future.delayed(Duration(seconds: 3), () => "데이터 로딩 완료!");
}

void main() {
  print("데이터 요청 중...");
  fetchData().then((data) {
    print(data); // 3초 후에 "데이터 로딩 완료!" 출력
  });
  print("다른 작업 실행 중...");
}

 
출력 결과:

데이터 요청 중...
다른 작업 실행 중...
(3초 후)
데이터 로딩 완료!

 
Future.delayed() 를 사용하여 3초 후 값을 반환하는 비동기 함수
then()을 사용하여 Future 완료 후 결과값을 받아 처리
 
 
[ 테스트 ]
 


 
 
 


3️⃣ async/await을 활용한 Future 처리

📌 async/await을 사용하면 비동기 코드를 동기 코드처럼 작성 가능
📌 await 키워드는 Future가 완료될 때까지 기다림 (비동기 실행을 동기처럼 표현 가능)

 

🔹 async/await 예제 2: Future 결과를 기다려서 실행

Future<String> fetchUser() async {
  await Future.delayed(Duration(seconds: 2)); // 2초 대기
  return "사용자 정보 로딩 완료!";
}

void main() async {
  print("데이터 요청 중...");
  String result = await fetchUser(); // await으로 Future 결과 기다림
  print(result);
  print("다른 작업 실행 중...");
}

 
출력 결과:

데이터 요청 중...
(2초 후)
사용자 정보 로딩 완료!
다른 작업 실행 중...

 
async 함수 내부에서 await 사용 가능
Future의 실행을 기다린 후, 다음 코드 실행
 
 
 


4️⃣ 예외 처리 (try-catch)

📌 비동기 작업에서 발생하는 오류를 처리하는 방법
📌 try-catch 또는 catchError()를 활용하여 예외(Exception)를 잡을 수 있음

 

🔹 try-catch를 활용한 비동기 예외 처리

Future<String> fetchUserData() async {
  await Future.delayed(Duration(seconds: 2));
  throw Exception("데이터 로딩 실패!"); // 강제로 예외 발생
}

void main() async {
  try {
	  print("데이터 요청중...");
    String data = await fetchUserData();
    print(data);
  } catch (e) {
    print("오류 발생: $e");
  } finally {
    print("비동기 작업 종료");
  }
}

 
출력 결과:

데이터 요청중...
오류 발생: Exception: 데이터 로딩 실패!
비동기 작업 종료

try-catch를 활용하여 오류를 잡고 메시지 출력
finally 블록을 사용하여 작업 종료 메시지 출력 (성공/실패와 상관없이 실행됨)
 
 
 


5️⃣ Flutter API 호출 , 데이터 로딩

1. http 패키지 설치 (필수)

flutter pub add http

 
2. API 요청 코드 작성

import 'dart:convert';
import 'package:http/http.dart' as http;

Future fetchPost() async {
  final url = Uri.parse("<https://jsonplaceholder.typicode.com/posts/1>");

  try {
    final response = await http.get(url);
    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      print("✅ 게시글 제목: ${data['title']}");
      print("✅ 게시글 내용: ${data['body']}");
    } else {
      print("😱 API 요청 실패: ${response.statusCode}");
    }
  } catch (e) {
    print("❌ 오류 발생: $e");
  }
}

// ✅ 사용자 목록 가져오기
Future fetchUsers() async {
  final url = Uri.parse("<https://jsonplaceholder.typicode.com/users>");

  try {
    final response = await http.get(url);
    if (response.statusCode == 200) {
      List users = jsonDecode(response.body); // JSON 배열 변환
      print("✅ 총 사용자 수: ${users.length}");

      for (var user in users) {
        print("👤 사용자: ${user['name']} (📧 ${user['email']})");
      }
    } else {
      print("❌ 사용자 목록 불러오기 실패: ${response.statusCode}");
    }
  } catch (e) {
    print("❌ 오류 발생: $e");
  }
}

void main() async {
  print("🚀 데이터 요청 시작...");

  await fetchPost(); // 게시글 데이터 가져오기
  print("\\n📌 다른 작업 수행 중...\\n");

  await fetchUsers(); // 사용자 목록 가져오기
  print("\\n✅ 모든 데이터 로딩 완료!");
}

 
출력 결과:

🚀 데이터 요청 시작...
✅ 게시글 제목: sunt aut facere repellat provident occaecati excepturi optio reprehenderit
✅ 게시글 내용: quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto
✅ 총 사용자 수: 10
👤 사용자: Leanne Graham (📧 Sincere@april.biz)
👤 사용자: Ervin Howell (📧 Shanna@melissa.tv)
👤 사용자: Clementine Bauch (📧 Nathan@yesenia.net)
👤 사용자: Patricia Lebsack (📧 Julianne.OConner@kory.org)
👤 사용자: Chelsey Dietrich (📧 Lucio_Hettinger@annie.ca)
👤 사용자: Mrs. Dennis Schulist (📧 Karley_Dach@jasper.info)
👤 사용자: Kurtis Weissnat (📧 Telly.Hoeger@billy.biz)
👤 사용자: Nicholas Runolfsdottir V (📧 Sherwood@rosamond.me)
👤 사용자: Glenna Reichert (📧 Chaim_McDermott@dana.io)
👤 사용자: Clementina DuBuque (📧 Rey.Padberg@karina.biz)

✅ 모든 데이터 로딩 완료!

 
 
 
 


6️⃣ Future 여러 개 실행하기 (Future.wait())

📌 여러 개의 Future를 동시에 실행하고, 모두 완료되었을 때 한꺼번에 처리 가능

 

🔹 Future.wait() 예제

Future<String> fetchUserProfile() async {
  await Future.delayed(Duration(seconds: 2));
  return "사용자 프로필 데이터";
}

Future<String> fetchUserPosts() async {
  await Future.delayed(Duration(seconds: 3));
  return "사용자의 게시글 목록";
}

void main() async {
  print("데이터 요청 중...");

  // 두 개의 Future를 동시에 실행하고, 모든 작업 완료 후 결과 반환
  List<String> results = await Future.wait([
    fetchUserProfile(),
    fetchUserPosts(),
  ]);

  print("프로필: ${results[0]}");
  print("게시글: ${results[1]}");
}

 
출력 결과:

데이터 요청 중...
(약 3초 후)
프로필: 사용자 프로필 데이터
게시글: 사용자의 게시글 목록

 
Future.wait()를 활용하여 여러 비동기 작업을 동시에 실행
가장 오래 걸리는 작업(3초)까지 기다린 후 결과 출력
 
 
 


7️⃣ Stream (연속적인 데이터 처리)

📌 Stream은 여러 개의 비동기 데이터를 순차적으로 받아올 때 사용
📌 async*, StreamController, listen() 등을 활용하여 데이터 흐름 관리 가능

 

🔹 Stream 기본 예제

Stream<int> numberStream() async* {
  for (int i = 1; i <= 5; i++) {
    await Future.delayed(Duration(seconds: 1)); // 1초마다 값 전송
    yield i;
  }
}

void main() {
  numberStream().listen((number) {
    print("새로운 값: $number");
  });
}

 
출력 결과:

새로운 값: 1
(1초 후)
새로운 값: 2
(1초 후)
새로운 값: 3
(1초 후)
새로운 값: 4
(1초 후)
새로운 값: 5

 
async*와 yield를 사용하여 데이터를 순차적으로 응답
listen()을 활용하여 Stream 데이터를 지속적으로 받아올 수 있음
 
 
 


📌 오늘의 실습 과제

[실습 1] Future.delayed()를 활용하여 3초 후에 메시지 출력하는 함수 만들기
[실습 2] async/await을 사용하여 API 데이터를 기다린 후 결과 출력하는 함수 만들기
[실습 3] try-catch를 활용하여 오류 발생 시 예외 처리하는 코드 작성
[실습 4] Future.wait()을 사용하여 2개의 비동기 작업을 동시에 실행하고 결과 출력
[실습 5] Stream을 활용하여 1초마다 숫자를 출력하는 프로그램 작성
 
 
 

728x90