비동기 통신

Stupefyee's avatar
Dec 31, 2024
비동기 통신

1. 더미 데이터 통신(v1)

main.dart
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'home_page.dart'; void main() { runApp(ProviderScope(child: MyApp())); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } }
home_page.dart
import 'package:flutter/material.dart'; import 'home_body.dart'; class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: HomeBody(), ); } }
home_body.dart
import 'package:flutter/material.dart'; import 'package:mockapp/home_repository.dart'; class HomeBody extends StatelessWidget { @override Widget build(BuildContext context) { HomeRepository repo = const HomeRepository(); int one = repo.getOne(); List<int> list = repo.getList(); return Column( children: [ // 변수 삽입에 {} 유무의 차이 >> 있으면 연산 가능 Text("$one", style: TextStyle(fontSize: 50)), Expanded( child: ListView.builder( itemCount: 4, itemBuilder: (context, index) { return ListTile( leading: Text(("${list[index]}")), title: Text("내용")); }, ), ), ], ); } }
future_page.dart
import 'package:flutter/material.dart'; class FuturePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold(); } }
home_repository.dart
// SRP: 데이터를 가져오는 곳 (휴대폰 디바이스(파일), 휴대폰 DB, Firebase(외부서버), 내서버, 공공데이터서버) class HomeRepository { const HomeRepository(); List<int> getList() { return [1, 2, 3, 4]; } int getOne() { return 1; } }

2. riverpod

1. 개념

  • Flutter에서 상태 관리를 위한 패키지.
  • React의 Hooks 개념에서 영감을 받음.
  • Provider의 개선 버전으로 더 강력하고 유연함.

2. 특징

  1. Compile-time 안전성
      • 상태 관리 오류를 컴파일 단계에서 감지.
      • Null 또는 의존성 누락 문제 감소.
  1. 의존성 관리
      • 프로바이더 간 의존성을 효율적으로 설정 및 관리.
  1. Global 상태 관리
      • 전역 상태를 간단하고 안전하게 관리.
  1. Lazy Evaluation
      • 필요할 때만 상태를 생성하여 성능 최적화.

3. 장점

  • 코드 분리: 상태와 UI 분리로 유지보수 용이.
  • 테스트 가능: 상태를 쉽게 테스트 가능.
  • 유연성: 다양한 상태 관리 패턴 지원.

3. riverpod 없이 비동기 데이터 통신(v2)

💡
변경점
home_repository: asyncawait를 사용하여 비동기 통신
future_page: future_body생성
main.dart: HomePage() >> FuturePage()
home_repository.dart
class HomeRepository { const HomeRepository(); // async await 사용 >> Future<리턴타입> 지정 Future<List<int>> getList() async { List<int> response = await Future.delayed( // 3초 후에 실행됨!! Duration(seconds: 3), () { return [1, 2, 3, 4]; }, ); return response; } Future<int> getOne() async{ int response = await Future.delayed( Duration(seconds: 3), () { return 5; }, ); return response; } }
future_page.dart
import 'package:flutter/material.dart'; import 'future_body.dart'; // reiverpod 없이 데이터 가져오기 class FuturePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: FutureBody(), ); } }
future_body.dart (생성됨)
import 'package:flutter/material.dart'; import 'package:mockapp/home_repository.dart'; class FutureBody extends StatelessWidget { HomeRepository repo = const HomeRepository(); @override Widget build(BuildContext context) { return Column( children: [ // future >> Future를 반환하는 값넣음 FutureBuilder( future: repo.getOne(), // snapshot == 반환값 builder: (context, snapshot) { // 반환값이 있으면 값 반환 if (snapshot.hasData) { return Text("1", style: TextStyle(fontSize: 50)); } else { // 없으면 기다리기 return CircularProgressIndicator(); } }, ), Expanded( child: ListView.builder( itemCount: 4, itemBuilder: (context, index) { return ListTile( leading: Text(("${index + 1}")), title: Text("내용")); }, ), ), ], ); } }
main.dart
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mockapp/future_page.dart'; void main() { runApp(ProviderScope(child: MyApp())); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: FuturePage(), ); } }

4. riverpod으로 비동기 데이터 통신(v3)

💡
변경점
main: FuturePage() >> HomePage() home_body: StatelessWidget >> ConsumerWidget home_page_vm: reiverpod Provider
main.dart
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'home_page.dart'; void main() { runApp(ProviderScope(child: MyApp())); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } }
home_page.dart
import 'package:flutter/material.dart'; import 'home_body.dart'; class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: HomeBody(), ); } }
home_body.dart
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mockapp/home_page_vm.dart'; class HomeBody extends ConsumerWidget { @override Widget build(BuildContext contextm, WidgetRef ref) { int? one = ref.watch(homeProvider); if (one == null) { return Center(child: CircularProgressIndicator()); } else { return Column( children: [ Text("$one", style: TextStyle(fontSize: 50)), Expanded( child: ListView.builder( itemCount: 4, itemBuilder: (context, index) { return ListTile( leading: Text(("${index + 1}")), title: Text("내용")); }, ), ), ], ); } } }
home_page_vm.dart
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mockapp/home_repository.dart'; final homeProvider = NotifierProvider<HomePageVM, int?>(() { return HomePageVM(); }); class HomePageVM extends Notifier<int?> { HomeRepository repo = const HomeRepository(); @override int? build() { // 상태 초기화 코드 >> build에 작성해두는게 좋음 >> 어차피 한번 실행해야함 getOne(); // 상태 null 임시 초기화 return null; } Future<void> getOne() async { int one = await repo.getOne(); state = one; } }
로딩이 돌다가
로딩이 돌다가
화면 출력
화면 출력
💡
의존 관계 차이
Spring MVC: Controller > Service > Repository
Flutter MVVM: View > ViewModel > Repository
 
Share article

stupefyee