Utiliser JSON et Flutter

La plupart des applications utilisent un grand nombre de données qu’elles actualisent à partir de ressources. Avec flutter, on utilise généralement le format JSON pour créer une base de données mobilisable.

Générer un fichier JSON #

La méthode est simple, on va créer un fichier Json simple avec un éditeur Json disponible en ligne. On peut aussi en utiliser un en ligne mais pour la simplicité on va gérer notre Json de manière locale. Voici un exemple:

[
  {
    "year": 2012,
    "id": 1,
    "title": "Tesla Modèle S"
  },
  {
    "year": 2015,
    "id": 2,
    "title": "Tesla modèle X"
  }
]

Créer un modèle #

Pour pouvoir manipuler les données de notre fichier Json, il faut créer une class model c’est à dire qu’on va créer une collection d’objets qui vont décrire la structure de notre JSON. Par exemple cette classe va dire ce que va contenir chaque élément de notre collection ici, chaque élément contient un year, un id et un title. Grâce à cela on pourra facilement retourner ce JSON sous forme d’une liste et on pourra aussi cibler un élément en particulier.

On créer donc une class Car et on initialise les données selon leur type.

class Car{
  final int year;
  final int id;
  final String title;

  Car({this.year,this.id,this.title});

}

Pour bien comprendre la structure d’un modèle ce lien est bien fait. On va ensuite utiliser le constructeur factory qui va retourner un singleton pattern c’est à dire un patron de conception qui comme je l’ai dit plus haut permet de résumer notre fichier dart à un objet. La définition de wikipédia explique très bien cela en ce qu’il permet d’atteindre une grande efficacité avec peu de code.

class Car {
  final int year;
  final int id;
  final String title;

  Car({this.year, this.id, this.title});

  factory Car.fromJson(Map<String, dynamic> json) {
    return Car(
        year: json['year'] as int,
        id: json['id'] as int,
        title: json['title'] as String);
  }
}

Convertir le fichier JSON en liste #

Ensuite nous allons utiliser deux fonctions: une pour analyser les données de notre fichier JSON et une autre nous retourner les données.

List<Car> analyseCars(String responseBody){
  final parsedJson = json.decode(responseBody).cast<Map<String, dynamic>>();
  return parsedJson.map<Car>((json) => Car.fromJson(json)).toList();

}

Notez qu’ici nous mettez Cars au pluriel car nous en cherchons plusieurs. Ensuite, nous utilisons la fonction json.decode pour obtenir un résultat sous la forme d’un String, ici, responseBody. La méthode .cast va nous permettre d’accéder à la map de notre JSON et d’en récupérer une liste de String d’où .fromJson()).toList();

Puis on va créer la fonction pour récupérer les données comme suit:

Future<List<Car>> fetchCars() async {
  final response = await rootBundle.loadString('assets/json/jsonV5.json');
  return compute(analyseCars, response);
}

L’AssetBundle rootbundle permet de retourner notre fichier JSON stocké localement et va retourner une liste dont on pourra accéder aux Strings.

L’UI #

On va créer deux classes qui vont étendre deux StatelessWidget. Le premier va viser la connexion des données avec un FutureBuilder de List et dont on va gérer les différents stades des connexions.

class TestPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: FutureBuilder<List>(
          future: fetchCars(),
          builder: (context, AsyncSnapshot<List> snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.waiting:
                return Center(child: CircularProgressIndicator());
              default:
                if (snapshot.hasError) {
                  return Text('Error');
                } else {
                  return CarList(
                    cars: snapshot.data,
                  );
                }
            }
          }),
    ));
  }
}

Puis on va créer une seconde classe qui va une seconde classe qui va gérer un ListView.Builder qui va renvoyer une card. Cette la card pourra renvoyer toutes les données de notre fichier json puisque nous allons utiliser le int index et ensuite il nous suffit de rentrer les identifiants des données que l’on souhait voir apparaitre title, id, year.


class CarList extends StatelessWidget {
  final List<Car> cars;

  CarList({Key key, this.cars}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: cars.length,
        itemBuilder: (context, int index) {
          return Card(
            child: Text(cars[index].title),
          );
        });
  }
}

Et voilà le résultat final:

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

class Car {
  final int year;
  final int id;
  final String title;

  Car({this.year, this.id, this.title});

  factory Car.fromJson(Map<String, dynamic> json) {
    return Car(
      year: json['year'] as int,
      id: json['id'] as int,
      title: json['title'] as String,
    );
  }
}

class TestPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: FutureBuilder<List>(
          future: fetchCars(),
          builder: (context, AsyncSnapshot<List> snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.waiting:
                return Center(child: CircularProgressIndicator());
              default:
                if (snapshot.hasError) {
                  return Text('Error');
                } else {
                  return CarList(
                    cars: snapshot.data,
                  );
                }
            }
          }),
    ));
  }
}

class CarList extends StatelessWidget {
  final List<Car> cars;

  CarList({Key key, this.cars}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: cars.length,
        itemBuilder: (context, int index) {
          return Card(
            child: Text(cars[index].title),
          );
        });
  }
}

List<Car> analyseCars(String responseBody) {
  final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();

  return parsed.map<Car>((json) => Car.fromJson(json)).toList();
}

Future<List<Car>> fetchCars() async {
  final response = await rootBundle.loadString('assets/json/jsonV5.json');
  return compute(analyseCars, response);
}

Utiliser JSON et Flutter est don un très bon moyen d’obtenir une application qui exploite un grand nombre de données.

Vous pouvez retrouver nos autres tutoriels sur l’onglet “Documentation” dans le menu déroulant ou en cliquant ici