インターネットからデータを取得する
インターネットからデータを取得することは、ほとんどのアプリで必要です。
幸いなことに、Dart と Flutter は次のようなツールを提供しています。http
このタイプの作業用のパッケージ。
このレシピでは次の手順を使用します。
- を追加します。
http
パッケージ。 - を使用してネットワーク リクエストを実行します。
http
パッケージ。 - 応答をカスタム Dart オブジェクトに変換します。
- Flutterでデータを取得して表示します。
http
パッケージ
1.のhttp
パッケージが提供するのは、
インターネットからデータを取得する最も簡単な方法。
追加するには、http
パッケージを依存関係として、
走るflutter pub add
:
$ flutter pub add http
http パッケージをインポートします。
import 'package:http/http.dart' as http;
さらに、AndroidManifest.xml ファイルでは、 インターネット許可を追加します。
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />
2. ネットワークリクエストを行う
このレシピでは、サンプル アルバムをJSONプレースホルダーを使用してhttp.get()
方法。
のhttp.get()
メソッドはFuture
が含まれているResponse
。
-
Future
を操作するためのコア Dart クラスです。 非同期操作。 Future オブジェクトは可能性を表します 将来のある時点で使用可能になる値またはエラー。 - の
http.Response
クラスには、成功したプログラムから受け取ったデータが含まれています httpコール。
3. レスポンスをカスタム Dart オブジェクトに変換します。
ネットワークリクエストを行うのは簡単ですが、生のデータを扱うのは簡単です。Future<http.Response>
あまり便利ではありません。
あなたの生活を楽にするために、
を変換しますhttp.Response
Dart オブジェクトに変換します。
Album
クラス
を作成しますまず、Album
からのデータを含むクラス
ネットワークリクエスト。これにはファクトリ コンストラクターが含まれています。
を作成しますAlbum
JSONから。
JSON を手動で変換することは 1 つのオプションにすぎません。 詳細については、記事全文を参照してください。JSONとシリアル化。
class Album {
final int userId;
final int id;
final String title;
const Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
http.Response
にAlbum
変換する次に、次の手順を使用して、fetchAlbum()
を返す関数Future<Album>
:
- レスポンスボディをJSONに変換する
Map
と のdart:convert
パッケージ。 - サーバーがステータス コードを含む OK 応答を返した場合、
200、次に JSON を変換します
Map
にAlbum
を使用してfromJson()
ファクトリーメソッド。 - サーバーがステータス コード 200 の OK 応答を返さない場合、
その後、例外をスローします。
(サーバー応答が「404 Not Found」の場合でも、
例外をスローします。戻らないでください
null
。 調べるときに大事なこと のデータsnapshot
、以下に示すように。)
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
万歳! これで、インターネットからアルバムを取得する機能ができました。
4. データを取得する
電話してくださいfetchAlbum()
どちらかの方法でinitState()
またdidChangeDependencies()
方法。
のinitState()
メソッドは 1 回だけ呼び出され、その後は呼び出されません。
応答として API をリロードするオプションが必要な場合は、InheritedWidget
変更して、電話をdidChangeDependencies()
方法。
見るState
詳細については。
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
// ···
}
このFutureは次のステップで使用されます。
5. データを表示する
データを画面に表示するには、FutureBuilder
ウィジェット。
のFutureBuilder
ウィジェットには Flutter が付属しており、
非同期データ ソースの操作が簡単になります。
次の 2 つのパラメータを指定する必要があります。
- の
Future
一緒に働きたいと思っています。 この場合、未来は次から返されます。 のfetchAlbum()
関数。 - あ
builder
Flutterに伝える関数 に応じて何をレンダリングするか の状態Future
: 読み込み、成功、またはエラー。
ご了承くださいsnapshot.hasData
のみを返しますtrue
スナップショットに null 以外のデータ値が含まれている場合。
なぜならfetchAlbum
null 以外の値のみを返すことができます。
関数は例外をスローする必要があります
「404 Not Found」サーバー応答の場合でも同様です。
例外をスローすると、snapshot.hasError
にtrue
エラーメッセージを表示するために使用できます。
それ以外の場合は、スピナーが表示されます。
FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
)
fetchAlbum() が initState() で呼び出されるのはなぜですか?
便利ではあるものの、
API 呼び出しをbuild()
方法。
Flutter はbuild()
必要なときはいつでもメソッド
ビュー内の何かを変更するには、
そしてこれは驚くほど頻繁に起こります。
のfetchAlbum()
メソッド内に配置された場合build()
、繰り返します
再構築のたびに呼び出されるため、アプリの速度が低下します。
保管するfetchAlbum()
状態変数の結果は次のことを保証します
のFuture
は 1 回だけ実行され、その後はキャッシュされます。
再構築します。
テスト
この機能をテストする方法については、 次のレシピを参照してください。
完全な例
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
const Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
@override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}