플러터(Flutter)는 Google이 개발한 오픈소스 UI 소프트웨어 개발 키트(SDK)로, 모바일, 웹, 데스크톱 애플리케이션을 위한 고성능 UI를 구축하는 데 사용됩니다. 이 강좌에서는 플러터의 핵심 개념 중 하나인 ‘상태 관리’에 대해 설명하며, 특히 Stateful 위젯에 대해 자세히 알아보겠습니다. 강좌는 Stateful 위젯의 개념, 사용법, 그리고 이를 활용한 실용적인 예제로 구성되어 있습니다.
1. 상태 관리란 무엇인가?
상태 관리(state management)는 애플리케이션의 데이터와 UI를 동기화하는 기법을 말합니다. 사용자 인터페이스(UI)는 종종 애플리케이션의 상태에 따라 달라지며, 이 상태는 사용자 입력, 네트워크 요청, 타이머 등 다양한 요인에 의해 변할 수 있습니다. 플러터에서는 이러한 상태를 관리하기 위해 두 가지 주요한 종류의 위젯을 제공합니다: Stateful 위젯과 Stateless 위젯입니다.
2. Stateless 위젯과 Stateful 위젯
Stateless 위젯은 변하지 않는 상태를 가지며, 따라서 UI가 그려질 때마다 새로 고쳐질 필요가 없습니다. 반면, Stateful 위젯은 내부 상태를 가질 수 있으며, 이 상태가 변경되면 위젯을 재구성해야 합니다. 일반적으로 사용자와의 상호작용이나 비동기 작업을 수반하는 UI에서는 Stateful 위젯이 활용됩니다.
2.1 Stateless 위젯 예시
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text('Hello, world!');
}
}
2.2 Stateful 위젯 예시
class MyStatefulWidget extends StatefulWidget {
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State {
int _count = 0;
void _incrementCounter() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('You have pushed the button this many times: $_count'),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increment'),
),
],
);
}
}
3. Stateful 위젯의 구조
Stateful 위젯은 두 개의 클래스로 구성됩니다: 위젯 클래스와 상태 클래스입니다. 위젯 클래스는 사용자에게 표시될 UI의 스타일을 정의하고, 상태 클래스는 변할 수 있는 데이터와 해당 데이터를 변화시키는 로직을 포함합니다. 이 두 클래스는 서로 긴밀하게 연결되어 있어 State 클래스의 상태가 변경될 경우 build 메서드가 호출되어 UI가 새롭게 그려집니다.
4. Stateful 위젯의 생명주기
Stateful 위젯은 특정한 생명주기를 가지고 있습니다. 이 생명주기는 위젯의 생성, 업데이트 및 삭제와 관련된 다양한 메서드로 구성됩니다. 이러한 메서드는 상태 관리의 효율성을 보장하는 데 중요한 역할을 합니다. 주요 생명주기 메서드는 다음과 같습니다:
- createState: 위젯이 생성될 때 호출됩니다. 새로운 상태 객체를 반환해야 합니다.
- initState: 상태 객체가 생성된 후 처음으로 호출됩니다. 초기화 작업을 수행하는 데 적합합니다.
- didChangeDependencies: 위젯의 의존성이 변경될 때 호출됩니다. 주로 InheritedWidget과 함께 사용됩니다.
- build: UI를 정서하는 데 사용됩니다. 상태가 변경될 때마다 상태 객체의 build 메서드가 호출됩니다.
- setState: 상태를 변경하고 UI를 업데이트하기 위해 사용하는 메서드입니다.
- dispose: 객체의 수명이 끝났을 때 호출되며, 리소스를 정리하는 데 사용됩니다.
4.1 State 클래스의 생명주기 예시
class _MyStatefulWidgetState extends State {
@override
void initState() {
super.initState();
// 초기화 코드
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 의존성 변경 코드
}
@override
Widget build(BuildContext context) {
// UI 구축 코드
}
@override
void dispose() {
// 리소스 정리 코드
super.dispose();
}
}
5. 실제 Stateful 위젯 구현 예제
이제 Stateful 위젯을 실제로 구현하는 방법에 대해 알아보겠습니다. 간단한 카운터 애플리케이션을 만들어 보겠습니다. 사용자가 버튼을 클릭할 때마다 카운트가 증가하는 기능을 구현하겠습니다.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Stateful Widget 예제'),
),
body: CounterWidget(),
),
);
}
}
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State {
int _count = 0;
void _incrementCounter() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('버튼을 눌러서 카운트를 증가시키세요:'),
Text('$_count', style: Theme.of(context).textTheme.headline4),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increment'),
),
],
),
);
}
}
위 코드는 Flutter의 기본 구조를 활용하여 Stateful 위젯을 구현한 것입니다. 이 애플리케이션은 ‘Increment’ 버튼을 클릭할 때마다 카운트 값을 증가시키고, 증가된 값을 화면에 출력합니다.
6. 상태 관리 패턴
Stateful 위젯은 기본적으로 상태를 관리할 수 있도록 설계되었지만, 복잡한 애플리케이션에서는 더 나은 상태 관리 패턴이 필요할 수 있습니다. 여러 가지 상태 관리 패턴이 있으며, 여기서는 가장 일반적으로 사용되는 패턴을 소개하겠습니다.
6.1 Provider 패턴
Provider는 Flutter에서 가장 많이 사용되는 상태 관리 솔루션 중 하나입니다. Provider 패턴은 InheritedWidget을 기반으로 하고 있으며, 간단하게 상태를 관리하고 공유하는 데 유용합니다. 다음은 Provider를 사용하여 카운터 예제를 변경한 코드입니다.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
}
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners(); // 상태 변경 알림
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Provider 예제'),
),
body: CounterWidget(),
),
);
}
}
class CounterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of(context);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('버튼을 눌러서 카운트를 증가시키세요:'),
Text('${counter.count}', style: Theme.of(context).textTheme.headline4),
ElevatedButton(
onPressed: counter.increment,
child: Text('Increment'),
),
],
),
);
}
}
6.2 BLoC 패턴
BLoC(Business Logic Component) 패턴은 앱의 비즈니스 로직을 UI에서 분리하여 관리하는 접근 방식입니다. Reactive programming을 따르며, 스트림을 사용하여 데이터 흐름을 제어합니다. BLoC 패턴에 대한 자세한 내용은 추후 강좌에서 다루겠습니다.
7. 결론
이번 강좌 및 예제를 통해 Stateful 위젯의 구조와 생명주기, 실제 사용 예를 살펴보았습니다. 플러터에서 상태 관리의 필요성과 다양한 상태 관리 패턴에 대해 알아보았습니다. Stateful 위젯은 사용자와의 상호작용을 통해 변화하는 UI를 구축하는 데 필수적인 요소로, 이를 잘 활용하면 더 효율적이고 유지보수가 쉬운 애플리케이션을 개발할 수 있습니다.
앞으로의 강좌에서는 더 많은 상태 관리 패턴, UI 구성 요소, 애플리케이션 아키텍처 등에 대해 단계적으로 학습할 예정입니다. 플러터를 통해 나만의 멋진 애플리케이션을 만들어보세요!