Dart에서 통신(실전)

통신을 통해 데이터를 받아와 출력하는 예제
화낼거양's avatar
Dec 31, 2024
Dart에서 통신(실전)
 
 

추가된 라이브러리 :

notion image
notion image
 
 
 

http_util.dart 파일 추가

 
import 'package:dio/dio.dart'; final Dio dio = Dio( BaseOptions( baseUrl: "https://jsonplaceholder.typicode.com", headers: { "Content-Type": "application/json" } ) );
 

주요 구성 요소

 
  1. Dio 라이브러리 가져오기:
    1. import 'package:dio/dio.dart';
      Dio 라이브러리를 가져와서 HTTP 요청을 처리할 수 있도록 합니다.
  1. Dio 인스턴스 생성:
    1. final Dio dio = Dio( BaseOptions( baseUrl: "https://jsonplaceholder.typicode.com", headers: { "Content-Type": "application/json" } ) );
      • Dio: Dio 클래스의 인스턴스를 생성합니다.
      • BaseOptions: BaseOptions 클래스를 사용하여 기본 설정을 지정합니다.
        • baseUrl: 기본 URL을 설정합니다. 이 예제에서는 "https://jsonplaceholder.typicode.com"을 사용하여 API 요청의 기본 URL을 지정합니다.
        • headers: 요청 헤더를 설정합니다. 여기에는 "Content-Type"이 "application/json"으로 설정되어 있습니다. 이는 요청이 JSON 형식임을 나타냅니다.
 
 

View

 
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mockapp/post_page_vm.dart'; class PostBody extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { Post? model = ref.watch(postProvider); if (model == null) { return Center(child: CircularProgressIndicator()); } else { return Column( children: [ Text("id : ${model.id}"), Text("userId : ${model.userId}"), Text("title : ${model.title}"), Text("body : ${model.body}"), Row(), ], ); } } }
 

동작 설명

 
  1. ConsumerWidget: PostBody 클래스는 ConsumerWidget을 상속합니다. 이는 build 메서드에서 WidgetRef 객체를 사용하여 Riverpod 상태 공급자(provider)와 상호작용할 수 있게 합니다.
  1. Post 상태 구독: ref.watch(postProvider) 메서드를 사용하여 postProvider의 현재 상태를 구독합니다. 이 상태는 Post? 타입의 model 변수에 저장됩니다.
  1. 상태 검사:
      • 만약 modelnull이라면, 데이터가 아직 로드되지 않은 상태로 간주하고 CircularProgressIndicator를 렌더링하여 로딩 중임을 표시합니다.
      • 만약 modelnull이 아니라면, 데이터를 성공적으로 로드한 상태로 간주합니다.
  1. 데이터 표시:
      • Column 위젯을 사용하여 Post 객체의 속성(id, userId, title, body)을 표시합니다.
      • Row 위젯이 추가되어 있지만 내용이 없는 상태입니다. 콘텐츠를 추가하거나 제거할 수 있습니다.
 
 
 

ViewModel

 
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mockapp/post_repository.dart'; class Post { int userId; int id; String title; String body; Post(this.userId, this.id, this.title, this.body); Post.fromMap(Map<String, dynamic> map) : userId = map["userId"], id = map["id"], title = map["title"], body = map["body"]; } final postProvider = NotifierProvider<PostPageVM, Post?>(() { return PostPageVM(); }); class PostPageVM extends Notifier<Post?> { PostRepository repo = const PostRepository(); @override Post? build() { // 상태 초기화 시작 init(); // 상태 null 초기화 return null; } Future<void> init() async { Post post = await repo.getPost(); state = post; } }
 

코드 설명

 

1. Post 클래스 (Model)

class Post { int userId; int id; String title; String body; Post(this.userId, this.id, this.title, this.body); Post.fromMap(Map<String, dynamic> map) : userId = map["userId"], id = map["id"], title = map["title"], body = map["body"]; }
  • Post 클래스: 게시물 데이터를 나타냅니다.
  • fromMap(Map<String, dynamic> map): Map 객체를 받아서 Post 객체를 초기화합니다.
 

2. NotifierProvider (State Management)

final postProvider = NotifierProvider<PostPageVM, Post?>(() { return PostPageVM(); });
  • postProvider: NotifierProvider를 사용하여 PostPageVM의 인스턴스를 제공합니다.
 

3. PostPageVM 클래스 (ViewModel)

class PostPageVM extends Notifier<Post?> { PostRepository repo = const PostRepository(); @override Post? build() { // 상태 초기화 시작 init(); // 상태 null 초기화 return null; } Future<void> init() async { Post post = await repo.getPost(); state = post; } }
  • PostPageVM: Notifier를 상속받아 상태 관리 및 데이터 로드를 처리합니다.
  • repo: PostRepository 인스턴스로, 데이터를 가져오는 역할을 합니다.
  • build() 메서드: 초기 상태를 설정하고 init 메서드를 호출합니다.
  • init() 메서드: 비동기적으로 데이터를 가져오고, 가져온 데이터를 상태(state)에 저장합니다.
 
 
 

Repository

 
// SRP : 데이터를 가져오는 곳 (휴대폰 디바이스(파일), 휴대폰 DB, Firebase(외부서버), 내서버, 공공데이터서버) import 'package:dio/dio.dart'; import 'package:mockapp/http_util.dart'; import 'post_page_vm.dart'; class PostRepository { const PostRepository(); Future<Post> getPost() async{ Response response = await dio.get("/posts/1"); // json 타입은 dio의 경우 Map 타입으로 받아준다. Map<String, dynamic> body = response.data; return Post.fromMap(body); } }
 
  • Dio 라이브러리 가져오기: Dio를 사용하여 API 요청을 보냅니다.
    • import 'package:dio/dio.dart'; import 'package:mockapp/http_util.dart'; import 'post_page_vm.dart';
       
  • PostRepository 클래스 정의:
    • class PostRepository { const PostRepository(); }
      PostRepository 클래스를 정의하고, 데이터를 가져오는 기본 역할을 담당합니다. 생성자는 상수 생성자이므로 불변 객체로 만들 수 있습니다.
       
  • getPost() 메서드:
    • Future<Post> getPost() async { Response response = await dio.get("/posts/1"); Map<String, dynamic> body = response.data; return Post.fromMap(body); }
    • Response: 비동기적으로 HTTP GET 요청을 보내고 응답을 받습니다. 이 예시에서는 "/posts/1" endpoint에서 데이터를 가져옵니다.
    • Map<String, dynamic> body: Dio의 응답 데이터를 Map<String, dynamic> 타입으로 변환합니다.
    • Post.fromMap(body): 변환된 Map 객체를 사용하여 Post 객체를 생성하고 반환합니다.
 
 
 
 
 
아래의 라이브러리는 log를 보기 좋게 사용하기 위한 라이브러리 입니다. (필수 다운 필요 X)
notion image
 
notion image
Share article

moohyun