[Flutter] 初心者でも簡単!APIでデータを取得してListViewに表示する方法

flutter で API からデータを取って ListView に表示する方法を、flutter_riverpod を使って実装してみました。

データはユーザ情報のAPIを使い、ListView を下に引っ張ってデータを更新するところまでをご紹介します。

動作サンプル

APIからユーザの一覧を表示して、データを更新しています。

使用するAPI(randomuser)

API は randomuser を使用します。こちらは、ランダムなユーザーデータを生成するための、フリーでオープンソースの API です。

JSON形式でのレスポンスは以下のフォーマットになります。

{
  "results": [
    {
      "gender": "male",
      "name": {
        "title": "mr",
        "first": "brad",
        "last": "gibson"
      },
      "location": {
        "street": "9278 new road",
        "city": "kilcoole",
        "state": "waterford",
        "postcode": "93027",
        "coordinates": {
          "latitude": "20.9267",
          "longitude": "-7.9310"
        },
        "timezone": {
          "offset": "-3:30",
          "description": "Newfoundland"
        }
      },
      "email": "brad.gibson@example.com",
      "login": {
        "uuid": "155e77ee-ba6d-486f-95ce-0e0c0fb4b919",
        "username": "silverswan131",
        "password": "firewall",
        "salt": "TQA1Gz7x",
        "md5": "dc523cb313b63dfe5be2140b0c05b3bc",
        "sha1": "7a4aa07d1bedcc6bcf4b7f8856643492c191540d",
        "sha256": "74364e96174afa7d17ee52dd2c9c7a4651fe1254f471a78bda0190135dcd3480"
      },
      "dob": {
        "date": "1993-07-20T09:44:18.674Z",
        "age": 26
      },
      "registered": {
        "date": "2002-05-21T10:59:49.966Z",
        "age": 17
      },
      "phone": "011-962-7516",
      "cell": "081-454-0666",
      "id": {
        "name": "PPS",
        "value": "0390511T"
      },
      "picture": {
        "large": "https://randomuser.me/api/portraits/men/75.jpg",
        "medium": "https://randomuser.me/api/portraits/med/men/75.jpg",
        "thumbnail": "https://randomuser.me/api/portraits/thumb/men/75.jpg"
      },
      "nat": "IE"
    }
  ],
  "info": {
    "seed": "fea8be3e64777240",
    "results": 1,
    "page": 1,
    "version": "1.3"
  }
}

ユーザモデルの作成

今回はユーザの画像、性、姓、名、メールアドレスを表示をしたいので、取得するデータは、gender, email, name, picture をするためのユーザモデルを作成します。

user.dart
class User {
  String gender;
  String email;
  Name name;
  Picture picture;

  User({this.gender, this.email, this.name});

  User.fromJson(Map json) {
    gender = json['gender'];
    email = json['email'];
    name = json['name'] != null ? new Name.fromJson(json['name']) : null;
    picture =
        json['picture'] != null ? new Picture.fromJson(json['picture']) : null;
  }

  Map toJson() {
    final Map data = new Map();
    data['gender'] = this.gender;
    data['email'] = this.email;
    if (this.name != null) {
      data['name'] = this.name.toJson();
    }
    return data;
  }
}

class Name {
  String title;
  String first;
  String last;

  Name({this.title, this.first, this.last});

  Name.fromJson(Map json) {
    title = json['title'];
    first = json['first'];
    last = json['last'];
  }

  Map toJson() {
    final Map data = new Map();
    data['title'] = this.title;
    data['first'] = this.first;
    data['last'] = this.last;
    return data;
  }
}

class Picture {
  String large;
  String medium;
  String thumbnail;

  Picture({this.large, this.medium, this.thumbnail});

  Picture.fromJson(Map json) {
    large = json['large'];
    medium = json['medium'];
    thumbnail = json['thumbnail'];
  }

  Map toJson() {
    final Map data = new Map();
    data['large'] = this.large;
    data['medium'] = this.medium;
    data['thumbnail'] = this.thumbnail;
    return data;
  }
}

API Requestを送信してデータをfetchする

ここでは 20 件データを取得し、レスポンスのステータスコードが 200 であれば、response.body の result を取得してユーザモデルの List に格納します。

network_request.dart
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;

import 'model/user.dart';

List parseUsers(String responseBody) {
  var list = json.decode(responseBody)['results'] as List;
  List users = list.map((model) => User.fromJson(model)).toList();
  return users;
}

Future> fetchUsers() async {
  final response = await http.get("https://randomuser.me/api/?results=20");
  if (response.statusCode == 200) {
    return compute(parseUsers, response.body);
  } else {
    throw Exception('Can\'t get users');
  }
}

riverpod の FutureProvider を定義して fetchUsers() を呼び出します。

final userStateFuture = FutureProvider>((ref) async {
  return fetchUsers();
});

ListViewで取得したデータを表示する

定義したプロバイダを watch して AsyncValue の List<User> に格納しそのデータを ListView で表示します。

データ読み込み時のインジケータを表示させるには、loading プロパティに指定します。

class MyHomePage extends ConsumerWidget {
  @override
  Widget build(BuildContext context,
      T Function<T>(ProviderBase<Object, T> provider) watch) {
    AsyncValue<List<User>> users = watch(userStateFuture);
    return Scaffold(
      appBar: AppBar(
        leading: Icon(Icons.menu),
        title: Text('Listing Users'),
        actions: [IconButton(icon: Icon(Icons.search), onPressed: () {})],
      ),
      body: users.when(
          loading: () => const Center(child: CircularProgressIndicator()),
          error: (error, stackTrace) =>
              Center(child: Text('${error.toString()}')),
          data: (value) {
            return RefreshIndicator(
              onRefresh: () async {
                await context.refresh(userStateFuture);
              },
              child: ListView.builder(
                  itemCount: value.length,
                  itemBuilder: (context, index) {
                    var fullName = value[index].name.title +
                        " " +
                        value[index].name.first +
                        " " +
                        value[index].name.last;
                    return Column(
                      children: [
                        Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: ListTile(
                            title: Row(
                              children: [
                                CircleAvatar(
                                  backgroundImage:
                                      NetworkImage(value[index].picture.large),
                                  radius: 24.0,
                                ),
                                SizedBox(width: 20.0),
                                Expanded(
                                  child: Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: [
                                      Text(
                                        fullName.toString(),
                                        style: TextStyle(fontSize: 17.0),
                                        overflow: TextOverflow.ellipsis,
                                      ),
                                      SizedBox(height: 10.0),
                                      Text(
                                        value[index].email.toString(),
                                        style: TextStyle(
                                            fontSize: 16.0, color: Colors.grey),
                                        overflow: TextOverflow.ellipsis,
                                      ),
                                    ],
                                  ),
                                )
                              ],
                            ),
                          ),
                        )
                      ],
                    );
                  }),
            );
          }),
    );
  }
}

RefreshIndicator で再表示する

ListView を下に引っ張って離した際に、データを取得して再表示するには、RefreshIndicator を使用します。ListView を wrap して onRefresh に context.refresh を指定します。

return RefreshIndicator(
  onRefresh: () async {
    await context.refresh(userStateFuture);
  },
  child: ListView.builder(

まとめ

今回は、APIでJSONデータを取得して ListView に表示するまでをご紹介しました。

この形式はよく使う方法だと思うので、他のAPIにも応用できると思います。flutter でのアプリ開発にご参考になればよいかと思います。

全体のソースコードは、github にあげてあります。

副業プログラミングで稼ぐやり方は、masamaru blogで解説していますのでぜひチェックしてみてください。

masamaru blog – 副業プログラミング、ブログ情報

転職を目指しているITエンジニアの方は、レバテックキャリアがおすすめですよ。

» レバテックキャリアの無料登録はこちら

Leave a Reply

Your email address will not be published. Required fields are marked *