[Flutter]플러터 Futurebuilder / Streambuilder란??
아직까지 나도 제대로 적용한적은 없고 그냥 구글링하면서 학습겸 정리하였다.
- FutureBuilder 공식문서 바로가기
앨범에서 이미지 가져오기, 배터리 표시, 파일 가져오기, http요청등 일회성 응답에 사용
- StreamBuilder 공식문서 바로가기
위치 업데이트, 음악 재생, 스톱워치 일부 데이터를 여러번 가져올때 사용
둘다 코드를 읽고 error 나 data 받는다.
- FutureBuilder 샘플코드
코드를 복사해서 실행하면 2초 로드후 데이터를 가져왔다는 성공 메시지를 띄우는 예제이다.
※FutureBuilder는 StatefulWidget의 자식클래스이다.
1. FutureBuilder
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final Future<String> _calculation = Future<String>.delayed(
const Duration(seconds: 2),
() => 'Data Loaded',
);
@override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: Theme.of(context).textTheme.headline2!,
textAlign: TextAlign.center,
child: FutureBuilder<String>(
future: _calculation, // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot<String> snapshot) { //data가 있으면 snapshot.data
List<Widget> children;
if (snapshot.hasData) {
children = <Widget>[
const Icon(
Icons.check_circle_outline,
color: Colors.green,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Result: ${snapshot.data}'),
)
];
} else if (snapshot.hasError) {
children = <Widget>[
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
children = const <Widget>[
SizedBox(
child: CircularProgressIndicator(),
width: 60,
height: 60,
),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting result...'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
);
},
),
);
}
}
- 간단한 예제
class Sample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureBuilder<SharedPreferences>(
future: SharedPreference.getInstance(),
builder: (BuildContext context, AsyncSnapshot<SharedPreferences> snapshot) {
String result;
if (snapshot.hasData == false) {
result = "Loading..."; }
else if (snapshot.data.getString("sessionKey")) {
result = "You has session key.";
} else {
result = "You has not session key.";
} return Center( child: Text(result); );
}
)
}
}
Async/await 키워드를 사용하여 비동기를 처리하는 것을 직관적으로 코드를 작성할 수 있다. FutureBuilder<T>에서 <T>는 비동기로 처리할 타입이 된다. builder에서는 AsyncSnapshot<T>인자를 통해서 <T>에 넘겨진 타입이 비동기로 처리되는 동안의 상태를 처리한다.
2. StreamBuilder
Stream?
스트림은 데이터가 들어오고 나가는 통로다.데이터가 변하는 걸 보고 있다가 그에 맞춰 적절한 처리.. 필터링(where)이나 수정(map), 버퍼링(take)같은 일을 한다.
StreamController?
스트림 컨트롤러는 여러 리스너(구독&상태)을 관리한다.
- 아래의 예제는 값이 추가 될때마다 출력하는 소스이다.
void main() {
StreamController ctrl = StreamController();
ctrl.stream.listen((data) {
print(data);
});
ctrl.add(1);
ctrl.add("Hello Stream");
ctrl.add({"first": 10, "tow": "20"});
ctrl.close();
}
플러터에서는 스트림 빌더(StreamBuilder)를 써서 스트림 처리를 한다.
스트림 빌더를 쓰면 setState() 를 쓰지 않고도 UI를 업데이트 할 수 있다.
또 항상 스트림의 최신값을 가져오니, 최신값을 확인할 필요가 없다.
- StreamBuilder 예제
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
StreamController<int> _events;
@override
initState() {
super.initState();
_events = new StreamController<int>();
_events.add(0);
}
void _incrementCounter() {
_counter++;
_events.add(_counter);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("StreamBuilder test"),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'You have pushed the button this many times:',
),
StreamBuilder(
stream: _events.stream,
builder: (BuildContext context, snapshot) {
return new Text(
snapshot.data.toString(),
style: Theme.of(context).textTheme.display1,
);
},
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: new Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
본문의 참조
https://zerodice0.tistory.com/225
https://ahang.tistory.com/16
https://eunjin3786.tistory.com/272