플러터 Flutter

[Flutter]플러터 Futurebuilder / Streambuilder란??

dev.mk 2021. 5. 30. 17:43
반응형

아직까지 나도 제대로 적용한적은 없고 그냥 구글링하면서 학습겸 정리하였다.

- FutureBuilder 공식문서 바로가기
  앨범에서 이미지 가져오기, 배터리 표시, 파일 가져오기, http요청등 일회성 응답에 사용

- StreamBuilder 공식문서 바로가기
  위치 업데이트, 음악 재생, 스톱워치 일부 데이터를 여러번 가져올때 사용


둘다 코드를 읽고 error data 받는다.

- FutureBuilder 샘플코드
  코드를 복사해서 실행하면 2초 로드후 데이터를 가져왔다는 성공 메시지를 띄우는 예제이다.

   ※FutureBuilderStatefulWidget의 자식클래스이다.

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

반응형