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 をするためのユーザモデルを作成します。
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 に格納します。
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エンジニアの方は、レバテックキャリアがおすすめですよ。