https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html
FutureBuilder
FutureBuilder 위젯은 Future를 취하고 Future의 상태를 기반으로 위젯 트리를 구축한다.
데이터를 가져오는 등 비동기 작업을 한 번 수행 후, 작업 진행중, 완료, 오류 발생여부에 따라
다른 UI를 렌더링하고자하는 경우에 적합하다.
파일, 데이터 가져오기, http요청 등 일회성 응답에 사용
async/await 키워드를 사용하여 비동기를 처리하며, FutureBuilder에서 는 비동기로 처리할 타입이 된다.
builder에서는 AsyncSnapshot인자를 통해서 에 넘겨진 타입이 비동기로 처리되는 동안의 상태를 처리한다.
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
//future안에서 값이 반환될 때마다 빌더를 새로 실행하게 됨
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<int>(
future: getNumber(),
builder: (BuildContext context, AsyncSnapshot<int> snapshot){
// snapshot.data: future에서 반환해주는 값
print('----data----');
print(snapshot.connectionState);
print(snapshot.data);
// error
if(snapshot.hasError){
final error = snapshot.error;
return Center(
child: Text('에러: $error'),
);
}
// 데이터가 존재하는지 확인
if(snapshot.hasData){
final data = snapshot.data;
return Center(
child: Text(data.toString()),
);
}
return Center(
child: Text('데이터가 없습니다'),
);
},
),
);
}
Future<int> getNumber() async {
await Future.delayed(Duration(seconds: 3));
final random = Random();
throw '에러!!';
return random.nextInt(100);
}
}
StreamBuilder
StreamBuilder 위젯은 Stream을 가져와 Stream의 최신 스냅샷을 기반으로 위젯 트리를 다시 빌드한다.
WebSocket 또는 데이터베이스에서 실시간 데이터 수신과 같이 지속적인 업데이트에 반응하려는 경우에 사용
FutureBuilder와 달리 async 가 아닌 async* 를 사용하고, return 대신 yield를 사용한다.
StreamBuilder를 사용하면 setState()를 쓰지 않고도 UI를 업데이트 및 최신의 값을 가져올 수 있다.
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
//future안에서 값이 반환될 때마다 빌더를 새로 실행하게 됨
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<int>(
stream: streamNumber(),
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
// snapshot.data // future에서 반환해주는 값을 받음
print('----data----');
print(snapshot.connectionState);
print(snapshot.data);
if (snapshot.connectionState == ConnectionState.active) {
// 다른 위젯을 보여줌
return SizedBox(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
Text(snapshot.data.toString()),
],
),
);
}
// error
if (snapshot.hasError) {
final error = snapshot.error;
return Center(
child: Text('에러: $error'),
);
}
// 데이터가 존재하는지 확인
if (snapshot.hasData) {
final data = snapshot.data;
return Center(
child: Text(data.toString()),
);
}
return Center(
child: Text('데이터가 없습니다'),
);
},
),
);
}
Stream<int> streamNumber() async* {
for (int i = 0; i < 10; i++) {
await Future.delayed(Duration(seconds: 1));
// if (i == 5) {
// throw '에러!!';
// }
yield i;
}
}
}
Stream<int> streamNumber() async* {
for(int i = 0; i < 10; i++){
await Future.delayed(Duration(seconds: 1));
if(i == 5){
throw '에러!!';
}
yield i;
}
}
공통
- 비동기로 데이터를 받아올 때 사용에 적절.
- 4가지의 ConnectionState가 존재
- ConnectionState.none - null 일 때 initialData, defaultValue 사용
- ConnectionState.active - Stream에서만 존재 / 진행중 (null이 아님)
- ConnectionState.waiting - 실행중
- ConnectionState.done - Future 또는 Stream이 종료되었을 때
차이점
FutureBuilder
단일 비동기 작업에 사용.
Future 완성을 기준으로 1회 빌드됨.
StreamBuilder
지속적인 비동기 작업에 사용.
Stream의 업데이트를 기반으로 여러 번 빌드됨.
async 가 아닌 async* 를 사용.
return 이 아닌 yield를 사용.