순서

  1. 의존성 추가하기 및 import 하기
  2. 객체 만들기
  3. 데이터 Fetch 하기
  4. Future로 api 호출하기


의존성 추가하기

dependencies:
  http: <latest_version>

# 받고자 하는 버전은 모르겠고 최신 버전으로 받고 싶다면 http: 만 입력해두 된다.


패키지 import하기

import 'package:http/http.dart' as http;


객체 만들기

JSON 형태로 넘어오는 데이터를 받기 위해 객체를 생성하자

class Album {
  final int userId;
  final int id;
  final String title;

  Album({this.userId, this.id, this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}


데이터 Fetch 하기

class _MyAppState extends State<MyApp> {
  Future<Album> futureAlbum;

  @override
  void initState() {
    super.initState();
    futureAlbum = fetchAlbum();
  }

fetch는 initState() 또는 didChangeDependencies() 에서 호출하세요.
initState() 메소드는 정확히 한 번 호출 된 다음 다시 호출 되지 않습니다.
변경에 대한 응답으로 API를 다시 로드하는 옵션을 원하면 didChangeDependencies()에 호출을 넣으세요.


Future로 api 호출하기#1

Future<Album> fetchAlbum() async {
  final response = await http.get('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(json.decode(response.body));
  } else {
    throw Exception('Failed to load album');
  }
}

Future는 비동기로 동작하는 자료형으로 데이터가 없을 때 보여줄 화면을 지정 했다가 ‘미래에’ 데이터가 들어오게 되면 채우는 형식이다. 자세한 내용은 밑에서 한번 더 설명할 것이다.


Future로 api 호출하기#2

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 CircularProgressIndicator();
  },
);

FutureBuilder에 future는 실행 할 메서드를 적고 builder에서 데이터를 받을 때 어떻게 처리할지 기입하면 된다.
첫 화면 진입 시 통신하는데 딜레이가 생겨 futureAlbum 함수에서는 에러는 뱉어낼 것이고 비동기 통신으로 나중에 데이터가 들어오면 builder 부분이 재실행되어 snapshot.hasData 의 부분이 리턴된다.


왜 fetchAlbum()을 initState()에서 호출할까?

편리하지만 build() 메소드에 API 호출을 넣지 않는 것이 좋습니다.
Flutter build()는 뷰에서 무엇이든 변경해야 할 때마다 메서드를 호출하며 이는 놀라 울 정도로 자주 발생합니다.
메서드에 fetch 호출을 남겨두면 build() 불필요한 호출로 API가 넘쳐 앱 속도가 느려집니다.



전체 코드

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('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(json.decode(response.body));
  } 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;

  Album({this.userId, this.id, this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
    );
  }
}

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  MyApp({Key key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Future<Album> futureAlbum;

  @override
  void initState() {
    super.initState();
    futureAlbum = fetchAlbum();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: 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 CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

출처 : https://flutter.dev/docs/cookbook/networking/fetch-data