FutureBuilder는 비동기 작업의 결과를 UI에 반영하기 위해 사용하는 Flutter 위젯입니다. 주로 API 호출, 파일 읽기, 데이터베이스 접근 등 시간이 소요되는 작업에서 사용됩니다. 강의 내용을 기반으로 FutureBuilder를 정리하고 설명을 덧붙이겠습니다.
FutureBuilder는 비동기 작업(Future)의 상태에 따라 UI를 동적으로 렌더링합니다.
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('FutureBuilder Example')),
body: FutureBuilderExample(),
),
);
}
}
class FutureBuilderExample extends StatefulWidget {
_FutureBuilderExampleState createState() => _FutureBuilderExampleState();
}
class _FutureBuilderExampleState extends State<FutureBuilderExample> {
// 비동기 작업 함수 정의
Future<int> fetchNumber() async {
await Future.delayed(Duration(seconds: 3)); // 3초 지연
return Random().nextInt(100); // 0~99 랜덤 숫자 반환
}
Widget build(BuildContext context) {
return FutureBuilder<int>(
future: fetchNumber(), // 실행할 Future
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
// 스냅샷의 상태에 따라 UI 분기 처리
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (snapshot.hasData) {
return Center(child: Text('Number: ${snapshot.data}'));
} else {
return Center(child: Text('No Data'));
}
},
);
}
}
future: 비동기 작업(Future 객체)을 전달합니다.builder: UI를 렌더링하는 콜백 함수. 비동기 작업의 상태를 나타내는 AsyncSnapshot을 사용합니다.AsyncSnapshot은 비동기 작업의 현재 상태와 데이터를 제공합니다.
connectionState: 작업 상태를 나타냅니다.none: Future가 초기화되지 않음.waiting: 작업 대기 중.active: 스트림이 활성 상태(스트림 빌더에서 주로 사용).done: 작업 완료.hasData: 데이터가 있는지 여부.hasError: 에러 발생 여부.data: 비동기 작업에서 반환된 데이터.error: 에러 내용.snapshot.hasError를 통해 에러 상태를 처리.snapshot.hasData로 데이터 존재 여부 확인.snapshot.connectionState에 따라 상태 분기.ConnectionState는 Future나 Stream의 상태를 나타냅니다.
| 상태 | 설명 | UI 예제 |
|---|---|---|
none | Future가 초기화되지 않음. | "No Future Provided" |
waiting | Future 작업 대기 중. | 로딩 스피너 |
active | Stream에서 데이터를 지속적으로 수신. | 현재 진행 중(스트림 전용). |
done | 작업 완료. | 데이터 출력 |
print('Connection State: ${snapshot.connectionState}');
Future와 AsyncSnapshot의 타입을 명시하면 코드 자동 완성과 타입 안정성을 높일 수 있습니다.
FutureBuilder<int>(
future: fetchNumber(),
builder: (context, AsyncSnapshot<int> snapshot) { ... }
);
Future에서 에러를 발생시키는 경우 UI에서 적절히 처리해야 합니다.
Future<int> fetchWithError() async {
await Future.delayed(Duration(seconds: 3));
throw Exception('An error occurred');
}
Future의 상태가 변경될 때마다 builder가 다시 실행됩니다. 디버깅을 위해 snapshot.data와 snapshot.connectionState를 출력하면 동작을 확인할 수 있습니다.
builder: (context, AsyncSnapshot<int> snapshot) {
print('Connection State: ${snapshot.connectionState}');
print('Data: ${snapshot.data}');
...
}
FutureBuilder는 동일한 Future를 여러 번 실행하지 않고 데이터를 캐싱합니다. 하지만 부모 위젯이 다시 빌드되면 Future를 다시 실행합니다.
FutureBuilder는 다음의 세 가지 핵심 패턴을 이해하면 쉽게 사용할 수 있습니다:
1. 연결 상태에 따라 분기 처리: snapshot.connectionState.
2. 에러 처리: snapshot.hasError와 snapshot.error.
3. 데이터 처리: snapshot.hasData와 snapshot.data.
FutureBuilder를 활용하면 비동기 작업의 상태를 UI에 쉽게 반영할 수 있습니다. 다음 시간에는 StreamBuilder를 다루며 실시간 데이터 처리에 대해 알아볼 수 있습니다.