Flutter는 Dart 언어를 기반으로 하며, 기본 문법은 변수 선언, 함수, 제어문, 컬렉션, 객체지향 프로그래밍, 그리고 위젯 구조로 구성됩니다. Dart 문법을 이해하는 것이 Flutter 앱 개발의 출발점입니다.
📝 Dart 기본 문법
- 프로그램 구조 모든 Dart 프로그램은 main() 함수에서 시작합니다.
-
dart
void main() { print('Hello, Flutter!'); } - 변수 선언
- 타입 명시: String name = '홍길동';
- 타입 추론: var age = 30;
- 동적 타입: dynamic value = '문자열';
- 상수
- final: 런타임에 값 결정
- const: 컴파일 타임에 값 결정
- 데이터 타입
- 숫자: int, double, num
- 문자열: String
- 불리언: bool
- 리스트: List<int> numbers = [1,2,3];
- 맵: Map<String, dynamic> person = {'name':'홍길동'};
- 집합: Set<String> names = {'홍길동','김철수'};
🔄 제어문과 반복문
- 조건문
-
dart
if (age > 18) { print('성인'); } else { print('미성년자'); } - 반복문
-
dart
for (var i = 0; i < 5; i++) { print(i); }
⚙️ 함수와 객체지향
- 함수
-
dart
int add(int a, int b) { return a + b; } - 클래스
-
dart
class Person { String name; int age; Person(this.name, this.age); }
🎨 Flutter 위젯 기본 문법
- StatelessWidget 상태가 변하지 않는 위젯
-
dart
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text('Hello Flutter')), body: Center(child: Text('안녕하세요!')), ), ); } } - StatefulWidget 상태가 변하는 위젯 (예: 버튼 클릭 시 값 변경)
🚨 주의할 점
- Null Safety: Dart는 null 안전성을 지원합니다. 변수 선언 시 String? name;처럼 nullable 타입을 명시해야 합니다.
- 비동기 프로그래밍: async/await를 활용해 네트워크 요청이나 파일 입출력을 처리합니다.
⚙️ Flutter 위쳇 생명주기
Flutter 위젯 생명주기는 위젯이 생성되고, 화면에 표시되며, 상태가 변경되고, 결국 소멸되는 전 과정을 의미합니다. 특히 StatefulWidget은 initState → build → dispose 흐름을 이해하는 것이 핵심입니다.
🟦 StatelessWidget 생명주기
- build
- 유일한 생명주기 메서드
- 위젯이 생성될 때 한 번 호출
- 상태가 없으므로 이후 변경 불가
dartclass HelloText extends StatelessWidget { @override Widget build(BuildContext context) { return Text('Hello Flutter!'); } }
🟩 StatefulWidget 생명주기 단계
단계설명활용 예시
| createState | State 객체 생성 (한 번만 호출) | 상태 관리 객체 준비 |
| initState | 초기화 로직 실행 | API 호출, 컨트롤러 초기화 |
| didChangeDependencies | 종속성 변경 시 호출 | MediaQuery, Provider 사용 |
| build | UI 렌더링, 상태 변경 시 재호출 | 화면 업데이트 |
| setState | 상태 변경 후 UI 갱신 | 버튼 클릭 시 카운트 증가 |
| didUpdateWidget | 부모 위젯 변경 시 호출 | 새로운 데이터 반영 |
| deactivate | 위젯 트리에서 제거 직전 호출 | 거의 사용되지 않음 |
| dispose | 리소스 해제 | 컨트롤러, Stream 정리 |
📌 예시 코드
dart
class CounterWidget extends StatefulWidget {
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0;
@override
void initState() {
super.initState();
print('initState 호출!');
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => _count++),
child: Text('$_count'),
);
}
@override
void dispose() {
print('dispose 호출!');
super.dispose();
}
}
🔔 앱 생명주기와 연계
- resumed: 앱이 포그라운드로 돌아와 사용자 입력 가능
- inactive: 포그라운드지만 입력 불가 (전화 수신 등)
- paused: 백그라운드 실행 중
- detached: 앱 종료 직전 상태
🚨 주의할 점
- Hot Reload 시 initState는 다시 실행되지 않음 → 앱 재시작 필요
- setState는 위젯이 mounted 상태일 때만 호출해야 오류 방지
- dispose에서 리소스를 반드시 해제하지 않으면 메모리 누수 발생
🔔 Dart 비동기 프로래밍
Dart 비동기 프로그래밍은 Future, async, await를 활용해 네트워크 요청, 파일 입출력처럼 시간이 오래 걸리는 작업을 효율적으로 처리하는 방식입니다. 프로그램이 멈추지 않고 다른 작업을 동시에 수행할 수 있도록 해줍니다.
🔑 핵심 개념
- Future 미래에 완료될 작업의 결과를 나타내는 객체.
-
dart
Future<String> fetchData() { return Future.delayed(Duration(seconds: 2), () => "데이터 완료"); } - async 함수가 비동기적으로 동작함을 선언. await를 사용하려면 반드시 필요.
- await Future가 완료될 때까지 기다린 후 다음 코드 실행.
-
dart
void main() async { print("데이터 요청 중..."); String result = await fetchData(); print(result); }
⚙️ 동작 방식
- 동기식 코드: 순차적으로 실행 → 오래 걸리는 작업에서 프로그램이 멈춤
- 비동기식 코드: 오래 걸리는 작업을 기다리지 않고 다른 작업을 계속 실행
- 장점:
- UI 응답성 유지
- CPU 자원 효율적 사용
- 여러 작업을 동시에 처리 가능
🛠️ 오류 처리
- then/catchError 방식
-
dart
fetchData().then((value) { print(value); }).catchError((error) { print("에러 발생: $error"); }); - try/catch 방식 (async/await)
-
dart
try { String result = await fetchData(); print(result); } catch (e) { print("에러 발생: $e"); }
🔄 여러 Future 처리
- Future.wait 여러 비동기 작업을 동시에 실행하고 모두 완료될 때까지 기다림.
-
dart
var results = await Future.wait([fetchData(), fetchData()]); print(results);
📌 Stream (연속 데이터 처리)
- Stream 여러 개의 비동기 이벤트를 순차적으로 전달받을 때 사용 (예: 채팅 메시지, 센서 데이터).
-
dart
Stream<int> countStream() async* { for (int i = 1; i <= 5; i++) { await Future.delayed(Duration(seconds: 1)); yield i; } }
🚨 주의할 점
- await는 반드시 async 함수 안에서만 사용 가능
- setState 같은 UI 갱신은 Future 완료 후 안전하게 호출해야 함
- 비동기 작업에서 리소스 해제를 잊으면 메모리 누수 발생
'Flutter' 카테고리의 다른 글
| Flutter 테트리스 소스 분석 (0) | 2026.05.27 |
|---|---|
| Flutter 개발환경 설치와 첫 실행 (0) | 2026.05.08 |