일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- pytorch
- BOF
- Widget
- Stream
- ML
- llm을 활용 단어장 앱 개발일지
- MDP
- 파이토치 트랜스포머를 활용한 자연어 처리와 컴퓨터비전 심층학습
- fastapi를 사용한 파이썬 웹 개발
- 백준
- Kaggle
- C++
- bloc
- FastAPI
- Computer Architecture
- rao
- Dreamhack
- MATLAB
- PCA
- Image Processing
- Flutter
- ARM
- 영상처리
- DART
- Got
- BAEKJOON
- study book
- Algorithm
- system hacking
- BFS
- Today
- Total
Bull
[Flutter] Bloc 상태 관리 본문
Bloc이란?
Bloc은 Business Logic Component의 약자로, 복잡한 상태 관리를 위한 강력한 패턴입니다. 이벤트 기반의 상태 관리 방식으로, 대규모 애플리케이션에서 효과적입니다.
- 설계 철학: Provider는 간단함과 유연성을 중시하며, Bloc은 명확한 구조와 테스트 용이성을 강조합니다.
- 상태 관리 방식: Provider는 ChangeNotifier를 통해 상태를 관리하고, Bloc은 이벤트와 상태를 구독하고 전송하는 방식으로 관리합니다.
- 복잡도: Provider는 비교적 배우기 쉽고 간단한 반면, Bloc은 학습 곡선이 더 가파릅니다.
- 성능: 두 솔루션 모두 성능이 우수하지만, Bloc은 더 큰 규모의 상태 관리에 적합합니다.
Bloc 실전 적용해보기
bloc으로 상태관리를 하기 위해 카운트 증가/감소를 통한 예제를 소개합니다.
상태 정의 및 로직 구현
파일 구조
그 전에 디렉토리 구조는 다음과 같습니다.
counter_bloc_example/
├── lib/
│ ├── bloc/
│ │ ├── counter_bloc.dart
│ │ ├── counter_event.dart
│ │ └── counter_state.dart
│ └── main.dart
파일 설명 (코드)
counter_event.dart
import 'package:equatable/equatable.dart';
abstract class CounterEvent extends Equatable {
const CounterEvent();
@override
List<Object> get props => [];
}
class CounterIncrementPressed extends CounterEvent {}
class CounterDecrementPressed extends CounterEvent {}
class CounterSetPressed extends CounterEvent {
final int value;
const CounterSetPressed(this.value);
@override
List<Object> get props => [value];
}
카운트가 증가/감소하거나 set하여 정해주는 함수를 정의합니다.
counter_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_event.dart';
import 'counter_state.dart';
class CounterBloc extends Bloc<CounterEvent, CounterState> {
CounterBloc() : super(const CounterState(0)) {
on<CounterIncrementPressed>((event, emit) {
emit(CounterState(state.counter + 1));
});
on<CounterDecrementPressed>((event, emit) {
emit(CounterState(state.counter - 1));
});
on<CounterSetPressed>((event, emit) {
emit(CounterState(event.value));
});
}
}
counter_event.dart에서 이벤트에 대한 정의에 로직을 구현해주는 부분입니다.
on((event, emit) { ... })와 emit(State) 메서드는 Bloc 패턴에서 이벤트를 처리하고 상태를 업데이트하는 데 사용됩니다.
event: 발생한 이벤트를 나타내는 객체입니다.
emit: 새로운 상태를 내보내는 함수입니다.
이 함수는 Bloc의 상태를 업데이트하는 데 사용됩니다.
emit을 호출하면 Bloc의 현재 상태가 새로운 상태로 변경되고, Bloc을 구독하고 있는 모든 UI 위젯이 새 상태를 반영하도록 다시 빌드됩니다.
하나의 예로, 증가하는 이벤트로직을 이렇게 해석해봅니다.
on:CounterIncrementPressed라는 이벤트는
emit:CounterState라는 상태를 가져와 상태를 변경해줍니다.
counter_state.dart
import 'package:equatable/equatable.dart';
class CounterState extends Equatable {
final int counter;
const CounterState(this.counter);
@override
List<Object> get props => [counter];
}
bloc을 통해 상태를 정의합니다. 이를 counter_bloc.dart에서 초기화 하거나 상태를 변경하는 로직을 수행할 때 emit의 파라미터로 포함되는 부분을 확인 할 수 있습니다.
상태를 통한 UI 적용(빌더) 및 부수효과 적용(리스너)
상태를 정의하였으니 상태에 대한 이용을 해야합니다.
이를 BlocBuilder와 BlocListener, BlocConsumer 세 가지로 나눠볼 수 있습니다.
BlocBuilder와 BlocListener, BlocConsumer를 사용하기 전에 위젯 클래스 부모에 BlocProvider를 선언해야합니다.
BlocProvider는 자식 위젯에서 Bloc을 사용할 수 있도록해주는 클래스입니다.
간단하기에 깊게 설명은 들어가지 않겠습니다.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => CounterBloc(),
child: CounterPage(),
),
);
}
}
BlocConsumer는 상태를 감지하여 UI를 다시 빌드합니다.
BlocListener는 똑같이 상태를 감지하지만 빌더와 다르게 부수적인 효과를 적용할 때 사용합니다.
BlocConsumer는 빌더와 리스너를 합쳐 UI 빌드와 부수효과를 적용을 동시에 하고 싶을 때 사용합니다.
아래 코드에서는 사용하지 않고 설명만 하겠습니다.
다음은 빌더를 통해 UI에서 원의 크기를 count에 따라 커졌다가 작아지는 애니메이션을 만들고, 상태 업데이트는 증가/감소/set 세 가지를 구현했습니다.
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'bloc/counter_bloc.dart';
import 'bloc/counter_event.dart';
import 'bloc/counter_state.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => CounterBloc(),
child: CounterPage(),
),
);
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final TextEditingController _controller = TextEditingController();
return Scaffold(
appBar: AppBar(title: Text('Flutter Bloc Counter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
BlocBuilder<CounterBloc, CounterState>(
builder: (context, state) {
double circleSize = state.counter % 2 == 0 ? 100.0 : 110.0;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Counter Value: ${state.counter}',
style: TextStyle(fontSize: 24.0),
),
SizedBox(height: 20.0),
AnimatedContainer(
duration: Duration(milliseconds: 500),
width: circleSize,
height: circleSize,
decoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
],
);
},
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Set Counter',
),
keyboardType: TextInputType.number,
),
),
ElevatedButton(
onPressed: () {
final int value = int.parse(_controller.text);
BlocProvider.of<CounterBloc>(context).add(CounterSetPressed(value));
},
child: Text('Set Counter'),
),
BlocListener<CounterBloc, CounterState>(
listener: (context, state) {
if (state.counter == 0) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Counter is zero!')),
);
}
},
child: Container(),
),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: () {
BlocProvider.of<CounterBloc>(context).add(CounterIncrementPressed());
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
SizedBox(height: 8.0),
FloatingActionButton(
onPressed: () {
BlocProvider.of<CounterBloc>(context).add(CounterDecrementPressed());
},
tooltip: 'Decrement',
child: Icon(Icons.remove),
),
],
),
);
}
}
요약정리
상태 및 이벤트 정의
이벤트 로직 구현(counter_bloc.dart)
- 상태 관리를 처리할 이벤트에 대하여 로직을 구현합니다.
class CounterBloc extends Bloc<[이벤트], [상태]> {
CounterBloc() : super(const 상태(초기값)) {
on<[이벤트]>((event, emit) {
emit(상태(업데이트 값));
});
...
}
이벤트 정의(counter_event.dart)
- 상태를 업데이트해줄 이벤트를 정의해줍니다.
상태 정의(counter_state.dart)
- 상태값에 대한 정의를 해주는 클래스입니다.
상태 사용 및 업데이트
BlocProovider
- 자식 위젯이 상태에 접근할 수 있도록 해줍니다.
- 인자*
- create: 생성할 상태 로직을 반환하도록 합니다.
- child: 접근 가능하도록 할 자식 위젯을 사용합니다.
BlocBuilder<[상태로직],[상태정의]>
- UI 등 상태를 이용한 로직을 구현하려면 이 클래스 내에서 적용합니다.
인자
- builder: 상태를 이용한 로직을 구현하고 원하는 위젯을 반환합니다.
BlocListener<[상태로직],[상태정의]>
- 상태를 감지하고 부수적인 로직을 추가할 수 있습니다.
인자
- listener: 상태를 이용한 부수적인 로직효과를 구현합니다.
- child: 빌더처럼 다시 업데이트 되지는 않지만 특정 위젯을 추가하고 싶다면 자식위젯으로 넣습니다.
BlocConsumer<[상태로직],[상태정의]>
- UI를 업데이트하고, 동시에 부수 효과를 처리해야 할 때 사용됩니다.
인자
- listener: 상태 변화에 따라 부수 효과를 처리합니다. 상태가 변경될 때마다 호출됩니다.
- builder: 상태 변화에 따라 UI를 업데이트합니다. 상태가 변경될 때마다 호출되어 새로운 위젯을 반환합니다.
'Software Framework > Flutter' 카테고리의 다른 글
[Flutter] Bloc Widget정리 (0) | 2024.07.15 |
---|---|
[Flutter] Font 적용하기 (로컬 저장 방식) (0) | 2024.07.10 |
[Flutter] Icon 사용하기 (0) | 2024.03.11 |
[Flutter] dart에 upbit api 호출하기 (1) | 2024.01.24 |
[Flutter] factory 생성자 (.fromJson) (0) | 2024.01.20 |