search
LoginSignup
86

More than 3 years have passed since last update.

posted at

updated at

【Flutter】JSONをデコードする

この記事は Flutter Advent Calendar 2018 - Qiita の20日目の記事です。

概要

FlutterにおけるJSONのデコード(エンコード)についてまとめます。

まとめ

小規模なプロジェクトでは手動デコードでもいいかもしれませんが、中規模以上のプロジェクトではコードジェネレーター(json_serializable)を使ったほうが良さそうです。

やり方

手動デコードの場合

Flutterはデフォルトで dart:convert というパッケージが入っているので
JsonCodec class で簡単にシリアライズできます。

sample.json
{
  "name": "John Smith",
  "email": "john@example.com"
}
main.dart
Map<String, dynamic> user = json.decode(json);

print('Howdy, ${user['name']}!');
print('We sent the verification link to ${user['email']}.');

json.decode() の戻り値の型は Map<String, dynamic> なので実行するまでJSONのValueがどの型になるかは分かりません。
また、デコード処理するロジックにキー名を書かないといけません。そのままStringで書いているのでtypoする可能性があります。

モデルクラスを使う場合

User というモデルクラスを用意し User.fromJson() / User.toJson() を定義します。

user.dart
class User {
  final String name;
  final String email;

  User(this.name, this.email);

  User.fromJson(Map<String, dynamic> json)
      : name = json['name'],
        email = json['email'];

  Map<String, dynamic> toJson() =>
    {
      'name': name,
      'email': email,
    };
}
main.dart
Map userMap = json.decode(json);
var user = new User.fromJson(userMap);

print('Howdy, ${user.name}!');
print('We sent the verification link to ${user.email}.');

エンコード・デコードのロジックをモデルクラスに内包することができました。
呼び出し側ではnameemailをStringではなくUserクラスのフィールドを参照しているので、typoしていた場合はコンパイルエラーで気がつくことができます。

コードジェネレーターライブラリを使う場合

pubspec.yamljson_annotationjson_serializableを追加します。

pubspec.yaml
dependencies:
  json_annotation: ^2.0.0

dev_dependencies:
  build_runner: ^1.0.0
  json_serializable: ^2.0.0

Userクラスを定義してJsonSerializableアノテーションを付与します。

user.dart
import 'package:json_annotation/json_annotation.dart';

// ジェネレートされたクラスからUserクラスのprivateメンバ変数にアクセスするため
part 'user.g.dart';

@JsonSerializable()
class User {
  User(this.name, this.email);

  String name;
  String email;

  // _$UserFromJsonが生成される
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

  // _$UserToJsonが生成される
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

FlutterプロジェクトのRootでコマンドラインで以下を実行。()

flutter packages pub run build_runner build

実行後、コードが生成されるので前述したやり方と同様にエンコードできます。

main.dart
Map userMap = json.decode(json);
var user = User.fromJson(userMap);

エンコード・デコードのロジックをコードジェネレーターに移譲することで、'name''email'を書く必要がなくなりました。

補足

JSONのキーと別名でモデルクラスのメンバ変数を定義した場合(例えばキーがsnake_caseでメンバ変数名をlowerCaseにしたい場合)はJsonKeyアノテーションをつけることでJSONのキー名を指定できます。

@JsonKey(name: 'first_name')
final int firstName;

以下のコマンドをFlutterプロジェクトのRootで実行することで、変更を検知してコード生成を自動化することもできます。

flutter packages pub run build_runner watch

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
86