본 강좌에서는 Flutter에서 Future
를 생성하고 출력하는 방법에 대해 상세히 설명하겠습니다. Future
는 Dart의 비동기 프로그래밍을 위한 핵심 개념으로, 비동기 작업이 완료될 때 값이나 오류를 반환하는 객체입니다. 이를 통해 우리는 UI를 블로킹하지 않고도 시간이 오래 걸리는 작업을 수행할 수 있습니다.
1. Future란?
Future
는 비동기 프로그래밍에서 미래의 결과를 나타내는 객체로, 비동기 작업이 완료될 때까지 기다렸다가 결과를 받을 수 있게 해줍니다. 예를 들어, HTTP 요청을 통해 데이터를 받아오는 경우, 요청이 끝날 때까지 기다리지 않고 다른 UI 작업을 진행할 수 있습니다.
1.1 Future의 상태
- 대기 중 (Pending): 작업이 완료되지 않은 상태입니다.
- 완료 (Completed): 작업이 완료되어 결과 값을 반환한 상태입니다.
- 오류 (Error): 작업 중 오류가 발생한 상태입니다.
2. Future 생성하기
Future
를 생성하는 방법은 크게 두 가지입니다. 첫 번째는 내장 메소드를 사용하는 것이고, 두 번째는 사용자 정의 함수를 통해 생성하는 것입니다.
2.1 내장 메소드 사용하기
Future.delayed
메소드를 통해 일정 시간 후에 작업이 완료되는 Future
객체를 생성할 수 있습니다. 다음은 2초 후에 메시지를 반환하는 예제입니다.
Future fetchData() {
return Future.delayed(Duration(seconds: 2), () {
return '데이터 로드 완료';
});
}
2.2 사용자 정의 함수 만들기
Future
를 반환하는 함수를 직접 만들어 데이터베이스나 API 요청을 처리할 수도 있습니다. 예를 들어, API에서 사용자 정보를 가져오는 함수를 생성해 보겠습니다.
Future fetchUser(int userId) async {
final response = await http.get('https://api.example.com/user/$userId');
if (response.statusCode == 200) {
return User.fromJson(json.decode(response.body));
} else {
throw Exception('사용자 로드 실패');
}
}
3. Future 출력하기
이제 우리가 생성한 Future
객체의 값을 Flutter 앱에서 출력하는 방법을 살펴보겠습니다. 이를 위해 FutureBuilder
위젯을 사용합니다. FutureBuilder
는 Future
의 상태에 따라 UI를 동적으로 업데이트해 줍니다.
3.1 FutureBuilder 사용하기
FutureBuilder
를 사용하기 위해서는 future
와 builder
매개변수를 정의해야 합니다. future
에는 비동기 작업을 수행할 Future
객체를 지정하고, builder
는 비동기 작업의 상태에 따라 UI를 구성하는 함수를 정의합니다.
class UserProfile extends StatelessWidget {
final int userId;
UserProfile(this.userId);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: fetchUser(userId),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('사용자 이름: ${snapshot.data.name}');
}
},
);
}
}
3.2 예외 처리
비동기 작업에서 오류가 발생할 수 있으므로, FutureBuilder
에서 snapshot.hasError
를 사용해 오류를 처리하는 것이 중요합니다. 올바른 예외 처리를 통해 사용자에게 명확한 피드백을 제공할 수 있습니다.
4. 전체 코드 예제
이제까지 배운 내용을 바탕으로 전체 예제를 살펴보겠습니다. 이 예제는 사용자 정보를 가져오는 API를 호출하고, 이를 화면에 출력하는 Flutter 앱입니다.
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
class User {
final String name;
User({required this.name});
factory User.fromJson(Map json) {
return User(name: json['name']);
}
}
Future fetchUser(int userId) async {
final response = await http.get('https://api.example.com/user/$userId');
if (response.statusCode == 200) {
return User.fromJson(json.decode(response.body));
} else {
throw Exception('사용자 로드 실패');
}
}
class UserProfile extends StatelessWidget {
final int userId;
UserProfile(this.userId);
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: fetchUser(userId),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('사용자 이름: ${snapshot.data.name}');
}
},
);
}
}
void main() => runApp(MaterialApp(home: Scaffold(body: UserProfile(1))));
5. 결론
이번 강좌에서는 Flutter에서 Future
를 생성하고, 이를 사용하여 비동기 작업을 효율적으로 처리하는 방법에 대해 배웠습니다. FutureBuilder
를 활용한 UI 구성은 데이터 로드 상태에 따라 동적으로 변할 수 있어 매우 유용합니다. 이러한 비동기 프로그래밍 기술은 복잡한 앱에서도 사용자의 경험을 개선하는 데 큰 도움이 됩니다.
Stream
과 async/await
개념도 함께 학습해 보세요.