2021. 2. 24. 10:43ㆍProgramming/Flutter
Async/await 키워드를 사용하여 비동기를 처리하는 건, 직관적으로 코드를 작성하는 데 몹시 중요하다. 그렇다면 Widget을 생성할 때, 초기 상태로 불러올 데이터가 비동기적인 처리를 거쳐야 할 때는 어떻게 해야할까? 여기서 FutureBuilder가 등장한다. 간단하게 설명해서 FutureBuilder는 비동기적인 처리를 진행하고, 결과에 따라 표시할 Widget을 반환해준다.
FutureBuilder에 대한 자세한 명세는 공식 문서를 참조하도록 하자.
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);
);
}
)
}
}
위는 Flutter의 SharedPreferences 패키지를 사용해서, SharedPreferences에 sessionKey값을 불러오는 코드다. SharedPreferences 패키지는 getInstance()
함수를 호출해서 인스턴스를 받아오는 팩토리 디자인을 사용하고 있으며, 이 과정에서 디스크에 접근하기 때문에 비동기로 처리된다.
예제 코드를 통해 FutureBuilder<T>
에서 <T>
는 비동기로 처리할 타입이 된다는 건 쉽게 눈치챌 수 있을 것이다. builder에서는 AsyncSnapshot<T>
인자를 통해서 <T>
에 넘겨진 타입이 비동기로 처리되는 동안의 상태값을 처리해준다.
FutureBuilder가 어떻게 상태를 처리하는지 확인하려면, FutureBuilder의 initState()
를 확인해보면 쉽게 알 수 있다.
@override
void initState() {
super.initState();
_snapshot = AsyncSnapshot<T>.withData(ConnectionState.none, widget.initialData);
_subscribe();
}
void _subscribe() {
if (widget.future != null) {
final Object callbackIdentity = Object();
_activeCallbackIdentity = callbackIdentity;
widget.future.then<void>((T data) { // 2
if (_activeCallbackIdentity == callbackIdentity) {
setState(() {
_snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data);
});
}
}, onError: (Object error) {
if (_activeCallbackIdentity == callbackIdentity) {
setState(() {
_snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error);
});
}
});
_snapshot = _snapshot.inState(ConnectionState.waiting); // 1
}
}
위의 코드는 _FutureBuilderState<T>
의 initState()
와 _subscribe()
이다. initState()
에서는 초기값 widget.initialData
으로 상태값 _snapshot
을 초기화한다. FutureBuilder<SharedPreferences>
를 선언할 때 initialData
를 넘겨주지 않았기 때문에 여기서는 null
로 초기화되며, AsyncSnapshot
의 data
가null
로 초기화됐기 때문에 AsyncSnapshot.hasData
의 값은 false
로 초기화된다.
이후 _subscribe()
함수 내부에서 widget.future
에 대한 처리방식을 확인할 수 있다. 크게 복잡한 건 없고, 처리 순서를 확인하면서 따라가면 쉽게 이해가 가능하다.
- 상태값
_snapshot
의ConnectionState
를waiting
으로 초기화해준다. 비동기 처리가 완료되기를 기다리고 있다는 중이라는 의미이다. widget.future.then
을 사용하여 비동기 처리를 진행한다. 처리가 완료될 경우 상태값_snapshot
에 완료된 데이터와 함께 새로운AsyncSnapshot
의 객체를 할당하며,_snapshot
의 내부 상태값ConnectionState
를done
으로 설정한다. 비동기 처리 중 에러가 발생한 경우에는,AsyncSnapshot.withError
를 호출하여 데이터 대신 에러를 설정해준다.
이제 FutureBuilder에서 비동기처리에 따라서 위젯을 표시하는 방식에 대해 이해하고, 꼭 FutureBuilder를 사용하지 않고StatefulWidget
에서 비동기 처리를 통한 화면 구성을 어떻게 할 수 있는지도 이해할 수 있을 것이다. 다만 FutureBuilder에는 에러 처리와 자원 할당 해제와 같은 세세한 내용이 포함되어있으므로, 가급적이면 FutureBuilder를 사용하여 비동기 처리에 따른 분기 처리를 해주도록 하자. :)
'Programming > Flutter' 카테고리의 다른 글
[Flutter] Dart에서 Generic을 사용할 때, 런타임에서 타입을 확인해보자. (0) | 2021.05.28 |
---|---|
[Flutter] Provider로 비동기 통신을 하여 FutureBuilder를 대체하기 (2) | 2021.03.25 |
[Flutter] Dart:io 패키지를 사용한 Http 통신 구현 및 주의점 (0) | 2021.02.04 |
비동기(Asynchronous)와 async/await, 그리고 여러개의 await에 대한 비동기 처리(Future.wait/Promise.all) (4) | 2021.01.29 |
플러터(Flutter) 사용시 참고할만한 사이트 (0) | 2021.01.04 |