비동기프로그래밍,future,async,await
카테고리: Dart
플러터에서 비동기 프로그래밍은 앱의 응답성을 유지하면서 긴 작업을 수행할 수 있도록 하는 중요한 개념입니다. 비동기 프로그래밍을 통해 네트워크 요청, 파일 입출력, 데이터베이스 쿼리 같은 시간이 걸리는 작업을 처리할 수 있습니다. 아래에서 비동기 프로그래밍의 기본 개념과 플러터에서의 구현 방법에 대해 자세히 설명하겠습니다.
1. 비동기 프로그래밍의 필요성
비동기 프로그래밍은 다음과 같은 이유로 필요합니다:
- 응답성 유지: 긴 작업을 수행하는 동안 UI가 멈추지 않도록 합니다. 이를 통해 사용자에게 더 나은 경험을 제공합니다.
- 리소스 효율성: 비동기 작업을 통해 CPU 자원을 효율적으로 사용할 수 있습니다. 다른 작업을 동시에 처리할 수 있습니다.
2. Dart의 비동기 프로그래밍
Dart는 비동기 프로그래밍을 지원하기 위해 Future
와 Stream
이라는 두 가지 주요 개념을 제공합니다.
Future
- Future: 비동기 작업의 결과를 나타내는 객체입니다. 작업이 완료되면 결과값을 반환하거나 오류를 발생시킬 수 있습니다.
- 작성법:
async
키워드로 정의된 함수 내에서await
를 사용하여 Future의 결과를 기다릴 수 있습니다.
Future<String> fetchData() async {
// 비동기 작업 시뮬레이션
await Future.delayed(Duration(seconds: 2));
return '데이터가 성공적으로 가져와졌습니다.';
}
Stream
- Stream: 연속적인 데이터 흐름을 나타냅니다. 주로 데이터가 여러 번 발생할 때 사용됩니다(예: 웹소켓, 사용자 이벤트).
- 작성법:
Stream
을 사용하여 데이터 흐름을 구독할 수 있으며,async*
키워드로 비동기 제너레이터를 정의할 수 있습니다.
Stream<int> countStream() async* {
for (int i = 1; i <= 5; i++) {
await Future.delayed(Duration(seconds: 1));
yield i; // 값을 발생시킴
}
}
3. 비동기 함수 사용 예제
아래는 플러터에서 비동기 함수를 사용하는 예제입니다. 이 예제는 API로부터 데이터를 비동기적으로 가져오는 방법을 보여줍니다.
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '비동기 프로그래밍 예제',
home: DataFetchPage(),
);
}
}
class DataFetchPage extends StatefulWidget {
@override
_DataFetchPageState createState() => _DataFetchPageState();
}
class _DataFetchPageState extends State<DataFetchPage> {
String _data = '데이터를 가져오는 중입니다...';
Future<void> _fetchData() async {
try {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
if (response.statusCode == 200) {
final jsonData = json.decode(response.body);
setState(() {
_data = jsonData['title'];
});
} else {
setState(() {
_data = '데이터를 가져오는 데 실패했습니다.';
});
}
} catch (e) {
setState(() {
_data = '오류 발생: $e';
});
}
}
@override
void initState() {
super.initState();
_fetchData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('비동기 데이터 가져오기'),
),
body: Center(
child: Text(_data, style: TextStyle(fontSize: 20)),
),
);
}
}
4. 코드 설명
Future<void> _fetchData()
: 비동기 함수로, 데이터를 가져오는 로직을 포함합니다.await
를 사용하여 비동기 요청을 처리하고, 결과에 따라 UI를 업데이트합니다.try-catch
블록: 데이터 요청 중 오류가 발생할 수 있으므로, 오류를 처리하기 위해try-catch
를 사용합니다.initState()
: 페이지가 초기화될 때_fetchData()
함수를 호출하여 데이터를 가져옵니다.
// ———————————————————-
플러터에서의 Future
, async
, await
는 비동기 프로그래밍을 구현하는 데 필수적인 요소입니다. 이들 개념은 Dart 언어에서 제공되며, 비동기 작업을 간편하게 처리할 수 있도록 도와줍니다. 아래에서 각각의 개념을 자세히 설명하겠습니다.
1. Future
Future
는 비동기 작업의 결과를 나타내는 객체입니다. 비동기 함수는 시간이 걸리는 작업을 수행할 때, 그 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있게 해줍니다.
- Future의 상태:
Future
는 세 가지 상태를 가집니다.- 대기 중(Pending): 비동기 작업이 진행 중인 상태입니다.
- 완료됨(Completed): 비동기 작업이 성공적으로 완료된 상태로, 결과값을 가지고 있습니다.
- 오류(Error): 비동기 작업이 실패한 상태로, 오류 정보를 가지고 있습니다.
-
Future 생성:
Future<String> fetchData() { return Future.delayed(Duration(seconds: 2), () { return '데이터가 성공적으로 가져와졌습니다.'; }); }
-
Future 사용 예:
void main() async { String data = await fetchData(); // Future의 결과를 기다림 print(data); }
2. async
async
는 함수를 비동기적으로 실행하도록 표시하는 키워드입니다. async
가 있는 함수는 항상 Future
를 반환합니다. 이 함수 내에서 await
키워드를 사용하여 비동기 작업의 결과를 기다릴 수 있습니다.
-
async 함수 정의:
Future<void> myAsyncFunction() async { // 비동기 작업 수행 await Future.delayed(Duration(seconds: 1)); print('비동기 작업 완료'); }
-
async 사용 예:
void main() async { print('작업 시작'); await myAsyncFunction(); // 비동기 작업을 기다림 print('작업 종료'); }
3. await
await
는 async
함수 내에서만 사용할 수 있는 키워드입니다. await
를 사용하면 Future
가 완료될 때까지 함수의 실행을 일시 중지합니다. 이로 인해 비동기 작업의 결과를 직관적으로 얻을 수 있습니다.
-
await 사용 예:
Future<void> fetchData() async { print('데이터를 가져오는 중...'); String data = await Future.delayed(Duration(seconds: 2), () { return '가져온 데이터'; }); print(data); // 두 초 후에 실행 } void main() { fetchData(); }
4. 전체적인 예제
아래는 Future
, async
, await
의 사용을 보여주는 전체 예제입니다. 이 예제에서는 API에서 데이터를 비동기적으로 가져오는 과정을 구현합니다.
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Future, Async, Await 예제',
home: DataFetchPage(),
);
}
}
class DataFetchPage extends StatefulWidget {
@override
_DataFetchPageState createState() => _DataFetchPageState();
}
class _DataFetchPageState extends State<DataFetchPage> {
String _data = '데이터를 가져오는 중입니다...';
// 비동기 함수: 데이터를 가져오는 함수
Future<void> _fetchData() async {
try {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
if (response.statusCode == 200) {
final jsonData = json.decode(response.body);
setState(() {
_data = jsonData['title']; // API로부터 가져온 데이터의 제목을 표시
});
} else {
setState(() {
_data = '데이터를 가져오는 데 실패했습니다.';
});
}
} catch (e) {
setState(() {
_data = '오류 발생: $e';
});
}
}
@override
void initState() {
super.initState();
_fetchData(); // 페이지가 초기화될 때 데이터 가져오기
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('비동기 데이터 가져오기'),
),
body: Center(
child: Text(_data, style: TextStyle(fontSize: 20)),
),
);
}
}
5. 코드 설명
- Future:
_fetchData
함수는Future<void>
로 선언되어 있으며, 비동기 작업을 포함합니다. - async:
_fetchData
함수는async
로 정의되어 있어 비동기 작업을 수행할 수 있습니다. - await:
await
를 사용하여 HTTP 요청이 완료될 때까지 기다립니다. 응답이 성공적이면 데이터를 UI에 반영합니다.
사용사례
Future
는 비동기 작업을 처리하는 데 매우 유용한 Dart의 기능입니다. 플러터 개발에서 Future
의 사용 사례는 다양하며, 아래에 몇 가지 일반적인 사용 사례를 설명하겠습니다.
1. 네트워크 요청
가장 일반적인 사용 사례 중 하나는 API 또는 서버와의 통신입니다. 데이터베이스나 RESTful API에 요청을 보내고 응답을 받을 때 Future
를 사용하여 비동기적으로 작업을 수행합니다.
Future<String> fetchPost() async {
final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));
if (response.statusCode == 200) {
return response.body; // 성공적인 응답
} else {
throw Exception('데이터를 가져오는 데 실패했습니다.');
}
}
2. 파일 입출력
로컬 파일 시스템에서 파일을 읽거나 쓸 때도 Future
를 사용할 수 있습니다. 비동기 파일 입출력을 통해 UI가 멈추지 않도록 할 수 있습니다.
import 'dart:io';
Future<String> readFile(String path) async {
final file = File(path);
return await file.readAsString(); // 파일 내용을 비동기적으로 읽기
}
3. 데이터베이스 쿼리
SQLite와 같은 로컬 데이터베이스에서 데이터를 조회할 때도 Future
를 사용하여 비동기적으로 쿼리 결과를 처리합니다.
Future<List<User>> fetchUsers() async {
final db = await openDatabase('my_db.db');
final List<Map<String, dynamic>> maps = await db.query('users'); // 비동기 쿼리
return List.generate(maps.length, (i) {
return User.fromMap(maps[i]); // 결과를 객체로 변환
});
}
4. 타이머 및 지연 작업
일정 시간 후에 작업을 수행해야 할 때도 Future
를 사용할 수 있습니다. 예를 들어, 특정 시간 후에 데이터를 새로 고치는 기능을 구현할 수 있습니다.
Future<void> delayTask() async {
await Future.delayed(Duration(seconds: 3)); // 3초 대기
print('작업 수행');
}
5. 애니메이션 및 트랜지션
애니메이션이나 화면 전환 효과를 비동기적으로 처리할 때 Future
를 사용할 수 있습니다. 예를 들어, 애니메이션이 완료된 후 다음 작업을 수행할 수 있습니다.
Future<void> animateAndDoSomething() async {
await animate(); // 애니메이션이 끝날 때까지 대기
print('애니메이션 완료 후 작업 수행');
}
6. 외부 라이브러리와의 통합
외부 라이브러리나 서비스와 통신할 때도 Future
를 사용하여 비동기 작업을 수행할 수 있습니다. 예를 들어, Firebase와 같은 클라우드 서비스에서 데이터를 가져오는 경우입니다.
Future<void> fetchFirebaseData() async {
final data = await FirebaseFirestore.instance.collection('users').get();
// 데이터 처리
}
결론
Future
는 비동기 처리를 통해 다양한 작업을 수행하는 데 매우 유용합니다. 네트워크 요청, 파일 입출력, 데이터베이스 쿼리, 타이머, 애니메이션, 외부 라이브러리와의 통합 등 다양한 상황에서 활용될 수 있습니다. 이러한 기능을 통해 플러터 애플리케이션의 응답성을 높이고 사용자 경험을 개선할 수 있습니다.
결론
Future
,async
,await
는 비동기 프로그래밍을 간편하게 처리할 수 있도록 도와주는 Dart의 주요 개념입니다.- 이러한 개념을 활용하면 비동기 작업을 쉽게 구현하고, UI의 응답성을 유지할 수 있습니다.
- 비동기 프로그래밍은 사용자 경험을 향상시키는 데 중요한 역할을 합니다. 이러한 개념을 잘 활용하여 더 나은 애플리케이션을 개발할 수 있습니다.
- 비동기 프로그래밍은 플러터 애플리케이션에서 매우 중요한 개념입니다.
Future
와Stream
을 사용하여 비동기 작업을 처리하면 앱의 응답성을 높이고, - 사용자 경험을 개선할 수 있습니다. 비동기 함수와 적절한 예외 처리를 통해 안정적인 애플리케이션을 개발할 수 있습니다.
댓글 남기기