굳이 왜 분리 해야할까?
배포를 위한 앱을 개발할 때 복잡한 구조의 위젯 트리를 만들었다고 했을 때 Scaffold 위젯을 통해서 많은 위젯이 제어. 이 과정 속에서 모든 하위 위젯들의 불필요한 업데이트가 진행.
-> 간단한 앱이면 크게 상관 없지만 무거운 앱일수록 사용자가 체감될 정도로 앱이 느려짐.
이러한 문제를 막기 위해 BLoC 사용하여 UI와 비지니스 로직을 분리하고 상태 관리를 하여 제어하고 싶은 위젯만 따로 제어해 효율적이고 클린 코드 설계 가능하며 유지보수 측면에서 유리.
├── lib
│ ├── src
│ │ ├── bloc
│ │ │ └── counter_bloc.dart
│ │ ├── components
│ │ │ └── counter_view.dart
│ │ └── ui
│ │ └── bloc_display_widget.dart
│ └── main.dart
├── pubspec.lock
├── pubspec.yaml
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocDisplayWidget() // BlocDisplayWidget 호출
);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Bloc 패턴"),
centerTitle: true,
elevation: 0.0,
),
body: CountView(), // Count만을 관리하는 CountView 호출
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {
// countBloc에서 add() 이벤트를 호출
countBloc.add();
},
),
IconButton(
icon: Icon(Icons.remove),
onPressed: () {
// countBloc에서 remove() 이벤트를 호출
countBloc.remove();
},
)
],
),
);
}
class CountBloc {
int _count = 0;
// StreamController을 통해 여러 이벤트를 처리
final StreamController _countSubject = StreamController.broadcast();
// count는 _countSubject.stream 을 구독하고 있는 모든 위젯에게 변경된 상태를 알림
Stream get count => _countSubject.stream;
// count 덧셈 이벤트 처리
add() {
_count++;
_countSubject.sink.add(_count); // _countSubject.sink 에다가 _count를 넣어준다.
}
// count 뺄셈 이벤트 처리
remove() {
_count--;
_countSubject.sink.add(_count); // _countSubject.sink 에다가 _count를 넣어준다.
}
// _countSubject을 종료
dispose() {
_countSubject.close();
}
}
class CountView extends StatelessWidget {
CountView({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return Center(
// 비동기 처리(StreamBuilder : 변화되는 값을 계속해서 감지)
// StreamBuilder를 통해 countBloc.count을 감지
child: StreamBuilder(
stream: countBloc.count, // countBloc.count => _countSubject.stream 을 구독중
initialData: 0,
builder: (BuildContext context, AsyncSnapshot snapshot) {
// AsyncSnapshot을 통해 들어온 snapshot을 UI에 뿌려준다.
if (snapshot.hasData) {
return Text(
snapshot.data.toString(),
style: TextStyle(fontSize: 80),
);
}
return CircularProgressIndicator();
},
),
);
}
하지만 BLoC 패턴의 경우 간단한 로직 구현에도 최소 4개의 클래스를 작성해야함.
그래서 Provider가 대안으로 나왔으므로 다음에은 Provider를 공부해보자.