중급
Future와 async/await
네트워크 요청과 파일 작업처럼 나중에 끝나는 작업을 다룹니다.
핵심 개념
Future와 async/await 주요 항목
Future의 의미
Future는 지금 당장 값이 없지만 나중에 성공하거나 실패하는 작업입니다.
언제 쓰나: Flutter 앱에서는 API 호출, 로컬 저장소 읽기, 파일 작업에서 자주 사용합니다.
Flutter에서: async/await는 비동기 코드를 순서대로 읽히게 만들어 줍니다.
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('Future의 의미', style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Text('Future는 지금 당장 값이 없지만 나중에 성공하거나 실패하는 작업입니다.'),
],
),
),
)
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xFFDCE6EF)),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFEEF7FB),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'Future의 의미',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w900),
),
)
],
),
)
Future의 의미
UI와 연결
비동기 작업은 로딩, 성공, 실패 상태를 나누어 화면에 표현해야 합니다.
언제 쓰나: FutureBuilder는 Future의 상태에 따라 UI를 분기할 때 사용할 수 있습니다.
Flutter에서: 비동기 작업 후 setState를 호출할 때는 위젯이 아직 mounted 상태인지 확인해야 합니다.
abstract class LessonRepository {
Future<List<String>> findTitles();
}
class LessonController {
LessonController(this.repository);
final LessonRepository repository;
}
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xFFDCE6EF)),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFEEF7FB),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'강의 목록',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w900),
),
),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
Chip(label: Text('로딩 완료')),
Chip(label: Text('Widget')),
Chip(label: Text('Layout')),
Chip(label: Text('State'))
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('3개의 강의를 불러왔습니다.')
],
)
],
),
)
강의 목록
로딩 완료WidgetLayoutState
3개의 강의를 불러왔습니다.
상세 설명
더 알아보기
비동기 결과를 화면에 붙일 때는 데이터보다 상태를 먼저 설계합니다. isLoading, data, error를 분리하면 버튼 재시도, 빈 화면, 오류 문구를 안정적으로 처리할 수 있습니다.
여러 요청이 서로 의존하지 않는다면 순서대로 await하기보다 Future.wait를 고려할 수 있습니다. 반대로 앞 요청 결과가 뒤 요청의 입력이면 순차 흐름이 더 명확합니다.
코드
예제
class LessonService {
Future<List<Lesson>> loadLessons() async {
try {
final response = await api.get('/lessons');
return response.map(Lesson.fromJson).toList();
} catch (error) {
throw Exception('강의 목록을 불러오지 못했습니다: $error');
}
}
}
Future<void> refresh() async {
setState(() => isLoading = true);
try {
lessons = await service.loadLessons();
} finally {
if (mounted) setState(() => isLoading = false);
}
}
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: const Color(0xFFDCE6EF)),
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: const Color(0xFFEEF7FB),
borderRadius: BorderRadius.circular(8),
),
child: const Text(
'강의 목록',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w900),
),
),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
Chip(label: Text('로딩 완료')),
Chip(label: Text('Widget')),
Chip(label: Text('Layout')),
Chip(label: Text('State'))
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('3개의 강의를 불러왔습니다.')
],
)
],
),
)
강의 목록
로딩 완료WidgetLayoutState
3개의 강의를 불러왔습니다.
주의 사항
실무에서 확인할 점
- 비동기 후 setState를 호출할 때 mounted 여부를 확인하세요.
- 서로 독립적인 Future는 Future.wait로 병렬 처리할 수 있습니다.
- 오류를 삼키지 말고 UI가 표시할 수 있는 형태로 변환하세요.
다음 단계
실습 체크리스트
Future 반환 함수 작성try/catch 처리로딩/오류 UI 만들기
- 출처세부 기준과 최신 변경 사항을 확인할 수 있습니다.
- Flutter API Reference클래스, 메서드, 생성자 세부 정의를 확인합니다.
- Dart languageDart 문법 자체가 궁금할 때 함께 봅니다.