Dio

Stupefyee's avatar
Dec 31, 2024
Dio
💡
Flutter HTTP 라이브러리

1. 특징

  • HTTP 요청(GET, POST, PUT, DELETE 등) 쉽게 처리
  • 인터셉터로 요청 및 응답 로깅, 토큰 처리 가능
  • 파일 업로드/다운로드 지원
  • Timeout 설정으로 네트워크 오류 관리
  • 자동 재시도 기능

2. 설치

  1. 다운로드 사이트 접속
  1. 설치 명령어 확인 및 실행
    1. 💡
      dart를 가져오지 않도록 주의
      $ flutter pub add dio
  1. 설치 완료 확인
    1. notion image

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

stupefyee