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などのモデルをパラメータで渡す事によって、loading
やerror
といったデータの状態と、取得完了後のデータをまとめてハンドリングすることが特徴です。
freezedなどを使ってユニオン型に状態を定義して扱っていた場合などは、AsyncValueにより必要なコード量を減らすことができます
実装
前提
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
型にパースするために使用しています。
- APIからのレスポンスを、json(
-
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の表示が変わっていることが確認できました
記事リスト取得中 | 取得完了 | 取得失敗 |
---|---|---|
以上、Volare Advent Calendar 2021の6日目記事でした!