Flutter HTTP 라이브러리
1. 특징
- HTTP 요청(GET, POST, PUT, DELETE 등) 쉽게 처리
- 인터셉터로 요청 및 응답 로깅, 토큰 처리 가능
- 파일 업로드/다운로드 지원
- Timeout 설정으로 네트워크 오류 관리
- 자동 재시도 기능
2. 설치
- 다운로드 사이트 접속
- 설치 명령어 확인 및 실행
dart를 가져오지 않도록 주의
$ flutter pub add dio
- 설치 완료 확인

3. 코드
1. 하나만 불러오기
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'post_page.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: PostPage(),
);
}
}
post_page.dart
import 'package:flutter/material.dart';
import 'package:mockapp/post_body.dart';
class PostPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: PostBody(),
);
}
}
post_body.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/post_page_vm.dart'; // ViewModel에서 데이터 상태를 관리하기 위한 파일 import
// PostBody 클래스 정의, ConsumerWidget을 상속하여 Riverpod 상태를 구독하는 위젯
class PostBody extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// postProvider를 통해 Post 객체의 상태를 구독
Post? model = ref.watch(postProvider);
// 상태에 따라 UI를 분기 처리
if (model == null) {
// model이 null인 경우 로딩 표시 (데이터가 아직 로드되지 않음)
return Center(child: CircularProgressIndicator());
} else {
// model이 존재하는 경우 데이터를 화면에 표시
return Column(
children: [
Text("id : ${model.id}"), // Post의 id 표시
Text("userId : ${model.userId}"), // Post의 userId 표시
Text("title : ${model.title}"), // Post의 제목 표시
Text("content : ${model.body}"), // Post의 본문 내용 표시
Row(), // 추가적인 UI 요소를 위한 빈 Row (아직 내용 없음)
],
);
}
}
}
post_page_vm.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/post_repository.dart';
// Post 모델 클래스 정의
class Post {
int userId; // 사용자 ID
int id; // 포스트 ID
String title; // 포스트 제목
String body; // 포스트 내용
// 생성자
Post(this.userId, this.id, this.title, this.body);
// Map 객체를 이용해 Post 객체 생성
Post.fromMap(Map<String, dynamic> map)
: userId = map["userId"],
id = map["id"],
title = map["title"],
body = map["body"];
}
// `postProvider` 정의, `PostPageVM` 클래스를 사용해 `Post?` 상태를 관리
final postProvider = NotifierProvider<PostPageVM, Post?>(() {
return PostPageVM();
});
// PostPageVM 클래스 정의, Notifier를 상속받아 상태 관리
class PostPageVM extends Notifier<Post?> {
PostRepository repo = const PostRepository(); // PostRepository 객체 생성
// 상태 초기화 메서드 (build 메서드 내에서 호출)
@override
Post? build() {
// `init()` 메서드를 호출하여 초기 상태 설정
init();
// 상태를 null로 초기화 (최초 상태는 null)
return null;
}
// 데이터 로딩 메서드
Future<void> init() async {
// PostRepository를 통해 포스트 데이터를 비동기적으로 가져옴
Post post = await repo.getPost();
// 가져온 데이터를 state에 설정
state = post;
}
}
post_repository.dart
import 'package:dio/dio.dart'; // Dio 패키지를 import하여 HTTP 요청을 보낼 수 있게 함
import 'package:mockapp/http_util.dart'; // dio 객체와 관련된 설정을 가져오는 유틸리티 파일
import 'package:mockapp/post_page_vm.dart'; // Post 모델과 관련된 클래스 파일 import
// PostRepository 클래스 정의
class PostRepository {
const PostRepository(); // 생성자
// 단일 Post 데이터를 가져오는 메서드
Future<Post> getPost() async {
// "/posts/1" 엔드포인트에서 GET 요청을 보내고, Response 객체를 받음
Response response = await dio.get("/posts/1");
// 응답 데이터를 body 변수로 저장 (Map 형식으로 반환됨)
Map<String, dynamic> body = response.data;
// Map 데이터를 Post 객체로 변환하여 반환
return Post.fromMap(body);
}
// 여러 개의 Post 데이터를 가져오는 메서드
Future<List<Post>> getPostList() async {
// "/posts" 엔드포인트에서 GET 요청을 보내고, Response 객체를 받음
Response response = await dio.get("/posts");
// 응답 데이터를 List<dynamic> 형식으로 저장
List<dynamic> list = response.data;
// 각 List 항목을 Post 객체로 변환하여 리스트로 반환
return list.map((e) => Post.fromMap(e)).toList();
}
}
2. 리스트 불러오기
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/post_list_page.dart';
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: PostListPage(),
);
}
}
post_list_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/post_list_body.dart';
import 'package:mockapp/post_list_page_vm.dart';
class PostListPage extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: PostListBody(),
floatingActionButton: FloatingActionButton(
child: Text("삭제"),
onPressed: () {
ref.read(postListProvider.notifier).deleteById(3);
},
),
);
}
}
post_list_body.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/post_list_page_vm.dart';
class PostListBody extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
List<Post2>? models = ref.watch(postListProvider);
if (models == null) {
return Center(child: CircularProgressIndicator());
} else {
return ListView.builder(
itemCount: models.length,
itemBuilder: (context, index) {
return ListTile(
leading: Text("${models[index].id}"),
title: Text("${models[index].title}"),
subtitle: Text("${models[index].body}"),
trailing: Text("유저아이디 ${models[index].userId}"),
);
},
);
}
}
}
post_list_page_vm.dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mockapp/post_repository.dart';
class Post2 {
int userId;
int id;
String title;
String body;
Post2(this.userId, this.id, this.title, this.body);
Post2.fromMap(Map<String, dynamic> map)
: userId = map["userId"],
id = map["id"],
title = map["title"],
body = map["body"];
}
final postListProvider = NotifierProvider<PostListPageVM, List<Post2>?>(() {
return PostListPageVM();
});
class PostListPageVM extends Notifier<List<Post2>?> {
PostRepository repo = const PostRepository();
@override
List<Post2>? build() {
// 상태 초기화 시작
init();
// 상태 null 초기화
return null;
}
Future<void> deleteById(int id) async {
// 1. 통신 코드
// 2. 상태 변경
List<Post2> posts = state!;
state = posts.where((p) => p.id != id).toList();
}
Future<void> init() async {
List<Post2> postList = await repo.getPostList();
state = postList;
}
}
post_repository.dart
import 'package:dio/dio.dart';
import 'package:mockapp/http_util.dart';
import 'package:mockapp/post_list_page_vm.dart';
import 'package:mockapp/post_page_vm.dart';
class PostRepository {
const PostRepository();
// json 통신시 Map으로 받아옴
Future<Post> getPost() async {
Response response = await dio.get("/posts/1");
// body >> data | response body 받아오기
Map<String, dynamic> body = response.data;
return Post.fromMap(body);
}
// json List 받아오기
Future<List<Post2>> getPostList() async {
Response response = await dio.get("/posts");
List<dynamic> list = response.data;
return list.map((e) => Post2.fromMap(e)).toList();
}
}
Share article