일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- tabbar
- Kotlin
- 앱바
- 앱
- appbar
- intent
- viewmodel
- 테스트
- 안드로이드
- DART
- LifeCycle
- CustomScrollView
- data
- 계측
- textview
- binding
- Compose
- textfield
- Coroutines
- android
- Flutter
- Button
- activity
- scroll
- TEST
- drift
- Dialog
- ScrollView
- Navigation
- livedata
- Today
- Total
Study Record
[Flutter] StreamBuilder 본문
✍ StreamBuilder Widget
FutureBuilder 와 비슷하게 stream 과 상호작용하며 값을 리턴 받을 때마다 다른 위젯들을 보여줘야 할 때 유용한 위젯이다.
StreamBuilder<T>({
Key? key,
T? initialData,
Stream? stream,
required Widget Function(BuildContext, AsyncSnapshot<T> ) builder,
})
stream 인자에 stream 을 설정하면 값(데이터 타입: T)을 리턴 받을 때마다 builder 함수가 호출되면서 AsyncSnapshot<T> 에 리턴 받은 값, 상태를 보고 판단하여 상황에 맞게 위젯들을 보여줄 수 있다. initialData가 null 이 아니면 초기 데이터 값이 null 이 아닌 initialData값으로 설정된다.
예시)
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: HomeScreen()));
class HomeScreen extends StatelessWidget {
HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: _MyStatefulWidget(),
);
}
}
class _MyStatefulWidget extends StatefulWidget {
_MyStatefulWidget({Key? key}) : super(key: key);
@override
State<_MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<_MyStatefulWidget> {
TextStyle textStyle = TextStyle(
color: Colors.black,
fontSize: 15.0
);
Stream<int> _calculate() async* {
for(int i=1; i<4; i++){
yield i;
await Future.delayed(Duration(seconds: 2));
}
}
@override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: Theme.of(context).textTheme.displayMedium!,
textAlign: TextAlign.center,
child: StreamBuilder<int>(
stream: _calculate(),
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("connectionState : ${snapshot.connectionState} data : ${snapshot.data}");
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text("snapshot state : ${snapshot.connectionState}", style: textStyle,),
Text("data : ${snapshot.data}", style: textStyle,),
Text("error : ${snapshot.error}", style: textStyle,),
ElevatedButton(
onPressed: () {
setState(() {});
},
child: Text("setsTate()"),
)
],
);
},
),
);
}
}
snapshot 은 작업 상태(snapshot.connectionState)와 반환값(snapshot.data) 정보를 알 수 있는데, connectionState는 4가지 상태를 가질 수 있다.
- ConnectionState.none : initalData만 있는 상태
- ConnectionState.waiting : future(비동기 작업)이 시작 단계에 있는 상태로 snapshot.data은 initialData인 상태이다.
- ConnectionState.active : 비동기 작업의 반환값(snapshot.data)이 null 이 아니지만 언제든 바뀔 수 있는 상태이다. StreamBuilder 에서만 사용된다.
- ConnectionState.done : 비동기 작업이 완료된 시점이며 반환값(snapshot.data)이 null 이 아니다.
또한, 비동기 작업 중 오류가 있다면 snapshot.hasError 값이 true 이며 초기 데이터(initialData)가 null 일 경우 비동기 작업의 반환값이 아직 없으면 snapshot.hasData 는 false을 리턴한다.
+ setState() 와 StreamBuilder
StatefulWiget 에서 setState() 를 하면 build 함수가 다시 실행되면서 StreamBuilder도 다시 만들어진다. 이 때, stream 을 함수로 설정하면 비동기 작업도 다시 실행된다. 이는 위의 예시에서 setState() 버튼을 눌렀을 때 다시 비동기 작업을 시작하고 이에 따른 UI도 변경된 모습까지 확인할 수 있다.
stream 을 변수로 설정하면 setState()를 해도 비동기 작업을 반복하지 않는다.
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: HomeScreen()));
class HomeScreen extends StatelessWidget {
HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: _MyStatefulWidget(),
);
}
}
class _MyStatefulWidget extends StatefulWidget {
_MyStatefulWidget({Key? key}) : super(key: key);
@override
State<_MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<_MyStatefulWidget> {
TextStyle textStyle = TextStyle(
color: Colors.black,
fontSize: 15.0
);
final Stream<int> _bids = (() {
late final StreamController<int> controller;
controller = StreamController<int>(
onListen: () async {
await Future<void>.delayed(const Duration(seconds: 1));
controller.add(1);
await Future<void>.delayed(const Duration(seconds: 1));
controller.add(2);
await controller.close();
},
);
return controller.stream;
})();
@override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: Theme.of(context).textTheme.displayMedium!,
textAlign: TextAlign.center,
child: StreamBuilder<int>(
stream: _bids,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("connectionState : ${snapshot.connectionState} data : ${snapshot.data}");
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text("snapshot state : ${snapshot.connectionState}", style: textStyle,),
Text("data : ${snapshot.data}", style: textStyle,),
Text("error : ${snapshot.error}", style: textStyle,),
ElevatedButton(
onPressed: () {
setState(() {});
},
child: Text("setsTate()"),
)
],
);
},
),
);
}
}
'Flutter > widget' 카테고리의 다른 글
[Flutter] 하위 항목 자동 줄바꿈 (Wrap Widget) (0) | 2023.02.22 |
---|---|
[Flutter] 가장 큰 위젯과 크기 동일하게 맞추기(IntrinsicHeight, IntrinsicWidth) (0) | 2023.02.22 |
[Flutter] FutureBuilder (0) | 2023.02.19 |
[Flutter] AlterDialog (+ showDialog) (0) | 2023.02.18 |
[Flutter] 위젯 겹치기 (Stack, Positioned) , 배경 불투명 (0) | 2023.02.18 |