🐣

[flutter] 1番シンプルにAPI取得して一覧表示する例を作成してみた

2021/12/09に公開約4,500字

こんにちは!

普段はWebアプリの開発をしているのですが、個人で作成したWebアプリをモバイルアプリにしたくて最近Flutterの勉強を始めました。

手始めにapiで取得したデータを一覧表示しようと思ったのですが、少し手間取りました。というのもシンプルにデータ取得して一覧表示するだけの記事がなかったからです。それっぽい記事を見つけても書き方が少し古いのか動かなかったり、複雑なことをしていてシンプルに一覧表示したいだけの需要を満たすものは見つかりませんでした。

公式の記事 はかなり参考になったのですが、返ってくるデータが配列ではなく一覧表示まではできなかったです。

試行錯誤の末、余計なことはせずAPI取得して一覧表示するまでできたのでここに残しておきます。

コード公開

まずコードはこちらです

main.dart
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'sentence.dart';

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

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

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter APP',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter APP'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<Sentence> _sentence = [];
  void fetchSentence() async {
    final response = await http.get(Uri.parse(
        '{APIのURL}'));
    if (response.statusCode == 200) {
      final List<dynamic> sentences =
          jsonDecode(utf8.decode(response.body.runes.toList()))['data'];
      setState(() {
        _sentence =
            sentences.map((sentence) => Sentence.fromJson(sentence)).toList();
      });
    } else {
      throw Exception('Failed to load sentence');
    }
  }

  
  void initState() {
    super.initState();
    fetchSentence();
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: ListView.builder(
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  title: Text(_sentence[index].text),
                );
              },
              itemCount: _sentence.length)),
    );
  }
}

sentence.dart

class Sentence {
  final String id;
  final String text;

  Sentence({
    required this.id,
    required this.text
  });

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

sentence.dart

先にsentence.dartについて見ていきます。
これは返ってくるデータの型を定義しているのかなと思っています。またJsonから定義した型に変換する処理も書いています。
このあたりは 公式の記事 を参考にしました。

ちなみに上記のsentence.dartはapiから以下のようなオブジェクトの配列が返ってくる場合の例です。

{
  id: '1111',
  text: 'thank you'
}

こちらは使用するAPIの返却値によって適宜変更が必要です。

main.dart

次にmain.dartについて見ていきます。
大きいのでいくつか分類して確認していきたいと思います。

ライブラリ・依存ファイル

import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'sentence.dart';

sentence.dartは先ほど作成したファイルです。
1行目のものは最初から入っていると思います。convertとhttpは今回追加しました。

インストール方法は以下を確認
httpのインストール方法: https://pub.dev/packages/http/install
convertのインストール方法: https://pub.dev/packages/convert/install

main

最初にflutterアプリを作成した時と変わっていないのでスキップ。

MyApp

最初にflutterアプリを作成した時と変わっていないのでスキップ。

MyHomePage

最初にflutterアプリを作成した時と変わっていないのでスキップ。

_MyHomePageState

_MyHomePageStateはapiでデータ取得、一覧表示をしています。

まず List<Sentence> _sentence = []; でstateを設定。

fetchSentence

final response = await http.get(Uri.parse(
        '{APIのURL}'));

http.getでHTTPのGETリクエストを実施。http.getの引数はURLの文字列ではなく、URLの文字列をUri.parseしたものである必要がありました。

final List<dynamic> sentences =
          jsonDecode(utf8.decode(response.body.runes.toList()))['data'];

取得したjsonデータを変換しています。まず utf8.decode(response.body.runes.toList()) を実行します。これをしないと文字化けしていました。そしてjsonをDecodeします。今回使用したapiのレスポンスは data にSentenceオブジェクトの配列が入っていたので最後に ['data'] を指定しました。

また List<dynamic> で型が何かは分からないけど配列であるということを宣言しています。

Sentence.fromJson(sentence)).toList() でSentenceの配列に変換し、setStateで _sentences に代入しています。

initState

最初に呼ばれる関数です。ここで先ほど作成したfetchSentenceを呼び出します。

ListView.builder

ListView.builderで一覧を作成します。itemCountで一覧に表示するアイテムの数を指定、itemBuilderでどんなものを表示するのか指定しています。
そしてListTileのtitleに_sentenceのtextを指定し、textが一覧表示されるようになっています。

まとめ

とりあえずこの方法でApiでデータを取得し、そのデータを一覧で表示するということができました。Flutter歴がめちゃくちゃ浅いので改善点が山ほどあると思いますが、最低限のことができました。

ここから、ナビゲーションバーを作成したり別のページを作成したりしていこうと思います。

Discussion

ログインするとコメントできます