【Flutter】APIからデータを取得し画面に表示(Flutter,VSCode,Api,Http)

flutter

1. 概要

上記記事で作成したAPIにアクセスしてJSONデータを取得し、スマホ画面に表示してみます。

  • Windows11
  • Flutter
  • AndroidManifest.xml
    • パーミッションを追加
      • android.permission.INTERNET
  • 依存ライブラリーを追加
    • http
  • Visual Studio Code
  • 「localhost」注意
  • 起動
    • スマホアプリ

対象としては開発を1年程やってて自分で最初から開発してみたい方になります。そのため細かい用語などの説明はしません。

2. プロジェクトを作成

2-1. こちらを参考

3. http(Dependencies)追加

3-1. こちらを参考

flutter pub add http

4. パーミッションを設定

4-1. Androidのマニフェストファイルにパーミッションを設定

<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />

5. モデルクラスを作成

5-1. <プロジェクト名>/lib/model/user.dart

import 'dart:convert';

class User {
  final int id;
  final String name;
  final String email;

  User({
    required this.id,
    required this.name,
    required this.email,
  });

  factory User.fromJson(Map<String, dynamic> json) => User(
        id: json["id"],
        name: json["name"],
        email: json["email"],
      );

  Map<String, dynamic> toJson() => {
        "id": id,
        "name": name,
        "email": email,
      };
}

User userModelFromJson(String str) => User.fromJson(json.decode(str));

String userModelToJson(User user) => json.encode(user.toJson());

6. サービスクラスを作成

6-1. <プロジェクト名>/lib/service/api_client.dart

import 'dart:convert';

import 'package:http_api/model/user.dart';
import 'package:http/http.dart' as http;

class ApiClient {
  Future<List<User>?> fetchUsers() async {
    final url = Uri.parse('http://123.45.678.9:8080/userList');
    try {
      final response = await http.get(url);
      if (response.statusCode == 200) {
        final List<dynamic> body = jsonDecode(response.body);
        final List<User> users =
            body.map((dynamic user) => User.fromJson(user)).toList();
        return users;
      } else {
        return null;
      }
    } catch (e) {
      // ignore: avoid_print
      print(e.toString());
    }
    return null;
  }
}
sondon@Sondon:~/dev/wsl$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 123.45.678.9  netmask 255.255.240.0  broadcast 123.45.678.255
        inet6 abcd::efg:5dff:feaf:58ce  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:af:58:ce  txqueuelen 1000  (Ethernet)
        RX packets 188569  bytes 552152761 (552.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 72216  bytes 6516813 (6.5 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 91442  bytes 464428044 (464.4 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 91442  bytes 464428044 (464.4 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

7. レポジトリクラスを作成

7-1. <プロジェクト名>/lib/repository/user_repository.dart

import 'package:http_api/service/api_client.dart';

class UserRepository {
  final apiClient = ApiClient();
  dynamic fetchUsers() async {
    return await apiClient.fetchUsers();
  }
}

8. ビューモデルクラスを作成

8-1. <プロジェクト名>/lib/view_model/user_viewmodel.dart

import 'package:http_api/repository/user_repository.dart';

class UserViewModel {
  final userRepository = UserRepository();
  dynamic fetchUsers() async {
    return await userRepository.fetchUsers();
  }
}

9. ビュークラスを作成

9-1. <プロジェクト名>/lib/view/user_page.dart

import 'package:flutter/material.dart';
import '../model/user.dart';
import '../view_model/user_viewmodel.dart';

// ignore: must_be_immutable
class UserPage extends StatelessWidget {
  UserPage({Key? key}) : super(key: key);

  final UserViewModel userViewModel = UserViewModel();

  List<User> users = [];
  Future getUsers() async {
    users = (await userViewModel.fetchUsers())!;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("User List"),
      ),
      body: FutureBuilder(
        future: getUsers(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(
              child: Text("LOADING"),
            );
          } else {
            if (users.isEmpty) {
              return const Center(
                child: Text("NO DATA"),
              );
            }
            return ListView.builder(
              itemCount: users.length,
              itemBuilder: (context, index) => ListTile(
                title: Text(users[index].name),
                subtitle: Text(users[index].email),
              ),
            );
          }
        },
      ),
    );
  }
}

10. メインクラスを修正

10-1. <プロジェクト名>/lib/main.dart

import 'package:flutter/material.dart';
import 'package:http_api/view/user_page.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Users',
      theme: ThemeData(primarySwatch: Colors.lime),
      home: UserPage(),
    );
  }
}

11. 結果

11-1. 結果

12. 参考

投稿者プロフィール

Sondon
開発好きなシステムエンジニアです。
卓球にハマってます。

関連記事

  1. flutter

    【Flutter】GoogleMapを使用したアプリの開発について P…

  2. flutter

    【Flutter】Flutter実装メモ  enumの拡張

  3. flutter

    【Flutter】GoogleMapを使用したアプリの開発について

  4. 【Widget of the Week】#4 AnimatedCont…

  5. 【Widget of the Week】#2 Expanded

  6. flutter

    【Flutter】アプリにAdmobバナー広告を設置

最近の記事

制作実績一覧

  1. Checkeys