LoginSignup
13
3

More than 1 year has passed since last update.

AsyncValueを使用したAPI通信の実装【Flutter】

Posted at

riverpodのstableのバージョン1.0.0が2021年11月5日に発表されました。(本記事公開日(2021/12/6)時点では1.0.2がstableの最新バージョン)

これによりFlutterを使用したアプリ開発の設計において、riverpodが選択される機会も増えてきたのではないかと思います。

今回は、そんなriverpodパッケージに含まれるAsyncValueクラスを利用した、API通信の実装方法について記していきます。

AsyncValueとは

AsyncValueは、非同期的に更新されるデータを安全に取り扱うためにRiverPodに内包されている、ユーティリティクラスです。

AsyncValue<T>で定義される総称型である為、データクラスやEntityなどのモデルをパラメータで渡す事によって、loadingerrorといったデータの状態と、取得完了後のデータをまとめてハンドリングすることが特徴です。

freezedなどを使ってユニオン型に状態を定義して扱っていた場合などは、AsyncValueにより必要なコード量を減らすことができます:sparkle:

実装

前提

QiitaのAPIから記事リストを取得して表示するサンプルです。

使用package

  • flutter_riverpod(ver 1.0.2)
    • riverpodをFlutterプロジェクトで使用する為のpackageです。
  • dio(ver 4.0.4)
    • 本記事ではHTTP Clientにdioを使用しています。(ここはretrofitでもchopperでもhttpでも何でも大丈夫です)
  • freezed(ver 1.0.2)
  • freezed_annotation(ver 1.0.0)
    • サンプルで表示する記事データのクラス(Article)をimmutableに扱うために使用しています。
  • json_serializable(ver 6.1.1)
    • APIからのレスポンスを、json(Map<String, dynamic>型)からArticle型にパースするために使用しています。
  • build_runner(ver 2.1.5)
    • .freezed及び.gファイルの自動生成を実行するのに必要です。

記事リスト取得

FutureProviderを使用し、APIからのレスポンスをArticle型のListとして提供しています。

final articleListProvider = FutureProvider<List<Article>>((ref) async {
  var dio = Dio();
  final response = await dio
      .get<List<dynamic>>('https://qiita.com/api/v2/items?page=1&per_page=20');
  return response.data!.map((data) => Article.fromJson(data)).toList();
});

このarticleListProviderをViewでwatchすることで、AsyncValueを扱うことができます。

記事リスト表示

前節で作成したarticleListProviderをwatchし、その状態を.when()でハンドリングしています。
今回の実装では、

  • 記事リストの取得中はインジケータを表示
  • 記事の取得に成功した場合は件数に応じて記事のタイトルとLGTM、コメントの数をListViewで表示
  • 記事の取得に失敗した場合は「エラーが発生しました」と表示

の3状態が存在します。

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final AsyncValue<List<Article>> articleList =
        ref.watch(articleListProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Qiita Client Demo'),
      ),
      body: Center(
        child: articleList.when(
          data: (articles) => ListView.builder(
            itemCount: articles.length,
            itemBuilder: (context, index) => Column(
              children: [
                ListTile(
                  title: Text(articles[index].title),
                  subtitle: Text(
                      'LGTM: ${articles[index].likes_count} コメント: ${articles[index].comments_count}'),
                  contentPadding: const EdgeInsets.all(16),
                  tileColor: Colors.lightGreen,
                ),
                const SizedBox(height: 8),
              ],
            ),
          ),
          error: (error, stackTrace) =>
              Text('エラーが発生しました。\n ${error.toString()}'),
          loading: () => const CircularProgressIndicator(),
        ),
      ),
    );
  }

実行結果

状態に応じてViewの表示が変わっていることが確認できました:thumbsup:

記事リスト取得中 取得完了 取得失敗
Simulator Screen Shot - iPhone 13 Pro - 2021-12-06 at 19.18.10.png Simulator Screen Shot - iPhone 13 Pro - 2021-12-06 at 19.18.13.png Simulator Screen Shot - iPhone 13 Pro - 2021-12-06 at 19.20.51.png

以上、Volare Advent Calendar 2021の6日目記事でした!

参考

13
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
3