티스토리 뷰
Flutter 앱 개발에서는 인터넷에서 데이터를 가져오는 작업이 필수적입니다. API를 호출하여 데이터를 가져오고 이를 UI에 표시하는 과정은 현대 모바일 앱의 핵심 기능 중 하나입니다. 이번 글에서는 Flutter에서 데이터를 가져오는 방법을 단계별로 설명하며, 실용적인 예제와 주요 팁을 제공합니다.
참고. Fetch data from the internet
인터넷에서 데이터 가져오기가 중요한 이유
Flutter 앱에서 데이터를 가져오는 주요 이유는 다음과 같습니다:
- 동적 데이터 표시: 최신 뉴스를 표시하거나 실시간 데이터를 제공.
- API 기반 앱: 서버와의 통신을 통해 사용자 요청 처리.
- 외부 데이터 활용: 외부 리소스에서 콘텐츠를 가져와 UI에 반영.
주요 구현 단계
1. http
패키지 추가
http
패키지는 Flutter에서 HTTP 요청을 처리하는 가장 간단한 방법을 제공합니다.
- 프로젝트에
http
패키지 추가: flutter pub add http
- 패키지 가져오기:
import 'package:http/http.dart' as http;
- AndroidManifest.xml에 인터넷 권한 추가:
<uses-permission android:name="android.permission.INTERNET" />
2. HTTP 요청 보내기
http.get()
메서드를 사용하여 API 엔드포인트에서 데이터를 가져옵니다. 예제:
Future<http.Response> fetchAlbum() {
return http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
}
3. JSON 데이터를 Dart 객체로 변환
API에서 가져온 JSON 데이터를 Dart 객체로 변환하면 데이터를 더 쉽게 처리할 수 있습니다.
- 모델 클래스 생성:
class Album { final int userId; final int id; final String title; Album({required this.userId, required this.id, required this.title}); factory Album.fromJson(Map<String, dynamic> json) { return Album( userId: json['userId'], id: json['id'], title: json['title'], ); } }
- 응답 데이터를 변환:
Future<Album> fetchAlbum() async { final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')); if (response.statusCode == 200) { return Album.fromJson(jsonDecode(response.body)); } else { throw Exception('Failed to load album'); } }
UI에서 데이터 표시하기
FutureBuilder 사용
FutureBuilder
는 비동기 작업 결과를 UI에 렌더링하는 데 유용합니다.
FutureBuilder<Album>(
future: fetchAlbum(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else {
return Text('No data found');
}
},
);
성능 최적화 및 팁
initState
에서 데이터 로드:fetchAlbum()
을initState
에 호출하여 불필요한 반복 호출을 방지합니다.@override void initState() { super.initState(); futureAlbum = fetchAlbum(); }
- 에러 처리:
서버 상태 코드가 200이 아닌 경우 적절히 처리하여 사용자에게 유용한 피드백을 제공합니다. - 상태 관리:
데이터가 복잡하거나 여러 화면에서 사용된다면Provider
,Riverpod
같은 상태 관리 패키지를 활용하세요. - 캐싱:
자주 요청하는 데이터는 로컬 스토리지에 캐싱하여 네트워크 호출을 최소화합니다.
샘플 프로젝트 구조
main.dart
: 앱의 진입점.- 모델 파일:
album.dart
로 데이터 모델 정의. - 네트워크 요청 파일:
api_service.dart
로 API 호출 로직 분리.
결론
Flutter로 인터넷에서 데이터를 가져오는 과정은 http
패키지와 JSON 파싱을 통해 간단히 구현할 수 있습니다. 위의 단계를 따라 구현하면, 동적 데이터를 UI에 효과적으로 반영할 수 있습니다. Flutter의 강력한 비동기 처리와 FutureBuilder
를 활용하여 사용자 경험을 한층 향상시켜 보세요.
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
const Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
'userId': int userId,
'id': int id,
'title': String title,
} =>
Album(
userId: userId,
id: id,
title: title,
),
_ => throw const FormatException('Failed to load album.'),
};
}
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}
'Flutter Cookbook' 카테고리의 다른 글
Flutter로 데이터 전송하기: 간단하고 명확한 가이드 (0) | 2024.12.03 |
---|---|
Flutter에서 인증된 요청 처리하기: 단계별 가이드 (0) | 2024.12.02 |
Flutter에서 데이터를 전달하는 방법: 간단하고 명확한 가이드 (0) | 2024.11.30 |
Flutter에서 데이터를 반환하며 화면 전환하기: 상세 가이드 (0) | 2024.11.29 |
Flutter에서 iOS Universal Links 설정하기: 딥 링크 구현 가이드 (2) | 2024.11.28 |