
ここまでで、Flutterを使った画面構築、状態管理、画面遷移までを一通り体験しました。
次に避けて通れないのが
API通信と、それに伴う非同期UIの扱い です。
業務アプリにおいて、API通信は「特別な処理」ではなく「日常動作」です。
そのためFlutterでは、API通信を前提にした設計が非常に自然に書けるようになっています。
このSTEPでは、HTTP通信の基本から、JSONの扱い、ローディングやエラーを含めた実務的なUI構成までをまとめて整理します。
HTTP通信
FlutterでHTTP通信を行う場合、まずは http パッケージを使うのが定番です。
内部的には非常にシンプルで、「URLを指定してリクエストを投げ、レスポンスを受け取る」という流れは、
JavaScriptやPHPとほぼ同じ感覚で書けます。
ポイントは、HTTP通信が必ず非同期になるという点です。
Flutterでは Future と async / await が言語レベルで統合されているため、通信処理をUIコードの中に自然に組み込めます。
この段階では、RepositoryやUseCaseの分離までは行わず、「まずは動く業務画面を作る」ことを優先します。
JSONパースとモデル設計
APIレスポンスは多くの場合JSONで返ってきます。
Flutterでは、JSONをMapとして直接扱うこともできますが、業務では必ず
モデルクラスを作ることをおすすめします。
理由は単純で、
・データ構造が明確になる
・補完が効く
・リファクタリングが安全になる
という、シニアエンジニアなら即座にメリットを感じられる点が揃っているからです。
Flutterでは
fromJson コンストラクタを用意するのが定番パターンで、APIレスポンスとUIの間に「型の壁」を作る意識が重要になります。
ローディング・エラー表示
API通信を行う以上、「通信中」と「失敗時」の状態を必ず考慮する必要があります。
Flutterではこの状態管理を
FutureBuilder や
setState と組み合わせて実装するのが基本です。
通信中はローディングを表示し、エラーが起きたらエラーメッセージを表示する。
そして、成功したときだけデータを描画する。
この3状態をUIとして明示的に分けることで、「止まっているように見えるUI」や「何が起きたか分からない画面」を防げます。
成果物:既存APIを叩く業務画面
早速、公開APIを叩いてデータを取得し、一覧表示する最小構成の業務画面を作ります。
ローディング、エラー、成功の流れが一目で分かる構成になっています。
事前にコマンドで実行
flutter pub add provider http
lib/main.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: UserListScreen(),
);
}
}
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) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
}
class UserListScreen extends StatefulWidget {
const UserListScreen({super.key});
@override
State<UserListScreen> createState() => _UserListScreenState();
}
class _UserListScreenState extends State<UserListScreen> {
late Future<List<User>> usersFuture;
@override
void initState() {
super.initState();
usersFuture = fetchUsers();
}
Future<List<User>> fetchUsers() async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/users'),
);
if (response.statusCode != 200) {
throw Exception('APIエラー');
}
final List data = jsonDecode(response.body);
return data.map((e) => User.fromJson(e)).toList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('ユーザー一覧')),
body: FutureBuilder<List<User>>(
future: usersFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return const Center(child: Text('データ取得に失敗しました'));
}
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
);
},
);
},
),
);
}
}
このコードで、
・API通信
・JSONパース
・ローディング表示
・エラー表示
・業務的な一覧画面
という一連の流れがすべて体験できます。
このステップのまとめ
このSTEPでは、Flutterにおける
API通信と非同期UIの基本を扱いました。
やっていること自体はJavaScriptやPHPと大きく変わりませんが、非同期処理とUIが一体化している設計は、Flutterならではの強みです。
この時点で、
「画面を作る」
「状態を持つ」
「APIを叩いて結果を表示する」
という、業務アプリ開発のコアはほぼ揃いました。
次のSTEPでは、これらを前提に、より実務向けな「設計の分離」や「規模を見据えた構成」に踏み込んでいくことになります。
0 件のコメント:
コメントを投稿