投稿の経緯
今回は以前投稿した、「httpを使ってAPIと通信する(データ取得編)」の続きです。
取得したデータをModelに格納してWidgetでデータを表示したいと思います。
前回の投稿はこちら↓
環境
Flutter version:3.7.3
Dart version:2.19.2
IDE:Android Studio
Modelに取得データを格納する
取得したデータの中から今回必要なweather
の部分をModelに格納します。
response: {
"lat":35.6514,
"lon":139.6367,
"timezone":"Asia/Tokyo",
"timezone_offset":32400,
"current":{
"dt":1678618031,
"sunrise":1678568265,
"sunset":1678610717,
"temp":288.71,
"feels_like":288.12,
"pressure":1022,
"humidity":69,
"dew_point":283.05,
"uvi":0,
"clouds":75,
"visibility":10000,
"wind_speed":4.63,
"wind_deg":160,
// 'weather'のデータを格納する
"weather":[
{
"id":803,
"main":"Clouds",
"description":"曇りがち",
"icon":"04n"
}
]
}
}
Modelクラスを作成します。
class WeatherModel {
final String main;
final String description;
final String icon;
WeatherModel({
required this.main,
required this.description,
required this.icon
});
factory WeatherModel.fromJson(Map<String, dynamic> json) {
var weather = json['weather'];
var data = weather[0];
var model = WeatherModel(
main: data['main'],
description: data['description'],
icon: data['icon']
);
return model;
}
}
.fromJsonでMap<String, dynamic>型
のjsonを受け取ってWeatherModel内でデータを格納するように書きました。呼び出し元の関数は以下の通り。
Future<WeatherModel?>get() async {
const lat = '35.65138';
const lon = '139.63670';
const key = 'aa50ce0598c22de20f75cf3ea31ac312';
const domain = 'https://api.openweathermap.org';
const pass = '/data/2.5/onecall';
const query = '?lat=$lat&lon=$lon&exclude=daily&lang=ja&appid=$key';
var url = Uri.parse(domain + pass + query);
debugPrint('url: $url');
var response = await http.get(url);
if (response.statusCode == 200) {
var body = response.body;
var decodeData = jsonDecode(body);
var json = decodeData['current'];
var model = WeatherModel.fromJson(json);
return model;
}
return null;
}
レスポンスのデータにアクセスするためにjsonDecode
したデータをWeatherModel.fromJson
に渡し、Future<WeatherModel?>型
でModelを返しています。
次は作成したModelを使ってWidgetを構築していきます。
ModelのデータでWidgetを構築する
APIと通信して、取得したデータをモデルに格納する一連のコードは非同期でおこなわれているので、Widgetの構築にはFutureBuilder
を使ってみます。
FutureBuilderとは
「Future = 非同期処理」の結果を受けてWidgetを構築する仕組みです。(便利!)
FutureBuilder(
future: , // 何かしらの非同期処理
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
// 処理終了後に呼ばれる
} else {
// 処理中に呼ばれる
}
}
);
非同期で終了を待ちたい処理をfuture
に、その結果を受けてWidgetを構築する処理をbuilder
に定義します。builderにはBuildContext
とAsyncSnapshot
の2つの引数が必要です。
この内、AsyncSnapshotにfutureで指定した非同期処理の結果が入るので、そのデータを使ってWidgetを構築します。ちなみにAsyncSnapshotには型を指定することもできます。
処理終了/処理中 なのかはsnapshot.hasData
で判断できます。
「true = 処理終了」「false = 処理中」といった状態です。非同期処理が終了しているとsnapshot.data
から結果にアクセスでき、そのデータを使ってWidgetを構築します。
注意点はhasDataのtrue/falseの両方にWidgetを構築する必要があるということです。
実際に使ってみた
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: get(),
builder: (BuildContext context, AsyncSnapshot<WeatherModel?> snapshot) {
if (snapshot.hasData) {
var data = snapshot.data;
return Scaffold(
body: Center(
child: Text('現在の天気は${data?.description}です!')
)
);
} else {
return const Scaffold(
body: Center(
child: Text('処理中...')
)
);
}
}
);
}
}
非同期処理中は「処理中...」と表示され、処理終了後はAPIから取得した天気情報が表示されるシンプルな画面です。
実際の動作
このように非同期処理の処理中/処理終了でWidgetを自動で切り替えてくれるFutureBuilder
は便利ですね!
おわりに
前回の記事と合わせたここまでの実装で
httpでAPIと通信して
↓
取得データをModelに格納して
↓
Modelを使ってWidgetを構築
といった一連の流れはできたかなと思います。
引き続きFlutterに関する学びを発信していきます。最後までご覧いただきありがとうございました!