Lire et Écrire du JSON dans Flutter
Lire et Écrire du JSON dans Flutter
-
Objectifs
- À la fin de ce cours, vous serez capable de :
- Comprendre le rôle et l’utilisation de JSON dans les applications Flutter.
- Charger des données JSON à partir d’un fichier ou d’une API.
- Convertir des données JSON en objets Dart (désérialisation).
- Convertir des objets Dart en JSON (sérialisation).
- Utiliser des outils comme json_serializable pour automatiser le processus de conversion.
-
Qu’est-ce que JSON?
- JSON est l’acronyme de JavaScript OBject Notation (Notation Objet issue deJavaScript)
- C’est un format léger d’échange de données
- Il est indépendant du langage de programmation. La syntaxe JSON est dérivée de la syntaxe de notation d’objet de JavaScript, mais le format JSON est uniquement en texte. Lecode de lecture et de génération de données JSON peut être écrit dans n’importe quel langage de programmation.
- Et il est «auto-décrivant» et facile à comprendre
- Le format JSON a été initialement spécifié par Douglas Crockford. C’est un programmeur et entrepreneur américain, notamment connu pour sa forte implication dans le développement du langage JavaScript et pour la création du format JSON.
-
Règles syntaxiques
- Il ne doit exister qu’un seul élément père par document contenant tous les autres : un élément racine.
- Tout fichier JSON bien formé doit être :
- soit un objet commençant par
{
et se terminant par}
, - soit un tableau commençant par
[
et terminant par]
. - Cependant ils peuvent être vides, ainsi
[]
et{}
sont des JSON valides. - Les séparateurs utilisés entre deux
paires/valeurs
sont des virgules. - Un objet JSON peut contenir d’autres objets
JSON
. - Il ne peut pas y avoir d’
éléments croisés
. - Il existe deux types d’éléments :
- Objets (Couples clé-valeur)
- Description : Les objets sont des collections de paires
clé-valeur
. Chaque clé est une chaîne de caractères, suivie d’undeux-points
: et de la valeur associée. - Syntaxe :
- Tableaux (Listes de valeurs)
- Description : Les tableaux sont des listes ordonnées de valeurs. Les valeurs peuvent être de n’importe quel type valide en JSON, y compris des objets, des tableaux, des chaînes, des nombres, etc.
- Syntaxe :
-
Valeurs possibles
- Primitifs : nombre, booléen, chaîne de caractères, null.
- Tableaux : liste de valeurs (tableaux et objets aussi autorisés) entrées entre crochets, séparées par des virgules.
- Objets : listes de couples « nom »: valeur (tableaux et objets aussi autorisés) entrés entre accolades, séparés par des virgules.
-
Exemple
- Voici un exemple JSON qui définit un objet « employé » contenant un tableau de trois objets d’employés, chacun ayant des propriétés comme « nom », « poste » et « parle » :
- Le format JSON est syntaxiquement identique au code pour créer des objets JavaScript.
- En raison de cette similitude, un programme JavaScript peut facilement convertir les données JSON en objets JavaScript natifs.
- Étant donné que le format JSON est uniquement du texte, il peut facilement être envoyé vers et depuis un serveur et utilisé comme format de données par n’importe quel langage de programmation.
- JavaScript a une fonction intégrée pour convertir une chaîne, écrite au format JSON, en objets JavaScript natifs :
JSON.parse()
. - Ainsi, si vous recevez des données d’un serveur, au format JSON, vous pouvez les utiliser comme n’importe quel autre objet JavaScript.
- Si vous voulez valider rapidement le fichier JSON, utilisez un outil en ligne comme JSONLint.
-
Lire du JSON dans Flutter
-
Charger un fichier JSON local
- Créer un fichier JSON dans le dossier assets : Exemple : assets/data.json
- JSON doit être correctement formaté pour être utilisé. Voici quelques points importants :
- Les clés (comme users, id, name) doivent être entourées de guillemets doubles (« ) : PAS de guillemets simples.
- Les valeurs chaînes de caractères (comme « John Doe ») doivent aussi être entourées de guillemets doubles.
- Les valeurs numériques (comme 1) doivent être écrites sans guillemets.
- Utilisez des virgules pour séparer les éléments dans une liste ou un objet, mais pas de virgule après le dernier élément.
- Ajouter le fichier JSON dans le fichier
pubspec.yaml
: - Créer un modèle pour les données
- Créez une classe Dart pour représenter les données JSON (par exemple, les « Users »). Voici un exemple de classe User :
-
Factory
est utilisée pour convertir un objet JSON en instance de User. -
Factory
fait référence à une méthode spéciale en Dart appelée factory constructor (ou constructeur de type « factory »). - Qu’est-ce qu’un Factory Constructor dans Dart ?
- Un
factory constructor
est une méthode utilisée pour créer une nouvelle instance d’une classe, mais de manière différente d’un constructeur classique (User(…)). - Un constructeur simple (ou constructeur classique) dans Dart est une méthode spéciale utilisée pour créer une instance d’une classe. Contrairement à un factory constructor, un constructeur simple n’ajoute pas de logique supplémentaire ou de personnalisation à la création d’une instance. Il sert principalement à initialiser les variables d’instance d’un objet.
- Avec un factory constructor :
- Vous pouvez contrôler le processus de création des objets.
- Vous pouvez retourner une instance existante au lieu d’une nouvelle.
- Vous pouvez transformer des données (par exemple, JSON) en objets.
- Pourquoi utiliser un Factory Constructor ici ?
- Dans le cas du JSON, les données sont souvent reçues sous forme d’un objet clé-valeur de type Map
. Ce constructeur permet de convertir facilement ces données JSON en une instance de la classe User. - Lire le fichier JSON:
- Utilisez la classe
rootBundle
de Flutter pour charger le fichier JSON et le convertir en données utilisables. Voici un exemple de fonction pour charger les données : - Explication des Composants
- Imports :
dart:convert
: Ce package fournit des fonctionnalités pour convertir des données entre les formats JSON et Dart. La fonction json.decode() est utilisée pour décoder une chaîne JSON en un objet Dart.flutter/services.dart
: Ce module permet d’accéder aux ressources de l’application, y compris les fichiers dans le dossier assets.- Déclaration de la fonction :
-
Future<List<dynamic>> loadJsonData() async
: Cette fonction est déclarée comme asynchrone (async), ce qui signifie qu’elle peut effectuer des opérations qui prennent du temps (comme le chargement d’un fichier) sans bloquer l’interface utilisateur. Le type de retour est un Future contenant une liste dynamique (List<dynamic>), ce qui signifie que la fonction renverra une liste d’objets une fois l’opération terminée. - Chargement du fichier JSON :
final String response = await rootBundle.loadString('assets/data.json');
rootBundle.loadString()
: Cette méthode charge le contenu d’un fichier dans le dossier assets et le renvoie sous forme de chaîne.await
: Cela indique que l’exécution de la fonction doit attendre la fin de cette opération avant de continuer. Cela garantit que la chaîne est complètement chargée avant de passer à l’étape suivante.- Décodage du JSON :
final data = json.decode(response);
json.decode(response)
: Cette fonction prend la chaîne JSON chargée et la convertit en un objet Dart. Dans ce cas, il renvoie une liste ou un objet, selon la structure du JSON.- Retourner les données :
return data;
: La fonction renvoie les données décodées. Cela peut être une liste de valeurs ou un objet, selon le contenu du fichier JSON.- DataService
- Construire une Interface Utilisateur
- Utilisez un
FutureBuilder
pour afficher la liste des employés. - Utiliser la Page dans main.dart
-
Charger des données JSON depuis une API
- Fichiers nécessaires
- user.dart (modèle de données)
- api_service.dart (service d’API)
- Interface (employee_views.dart
- main.dart (logique principale)
-
Convertir JSON en objets Dart (Désérialisation)
- Créer un modèle Dart correspondant au JSON :
- Utiliser le modèle :
- Construire une Interface Utilisateur
- Utilisez un FutureBuilder pour afficher les données récupérées :
{
"nom": "Alice",
"age": 30,
"ville": "Paris"
}
[
"pomme",
"banane",
"orange"
]
{
"employes": [
{
"nom": "Alice",
"poste": "Développeuse",
"parle": ["français","anglais"]
},
{
"nom": "Bob",
"poste": "Designer",
"parle": ["anglais","espagnol"]
},
{
"nom": "Charlie",
"poste": "Chef de projet",
"parle": ["français","allemand","Arabe"]
}
]
}
{
"users": [
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com"
},
{
"id": 2,
"name": "Jane Smith",
"email": "jane.smith@example.com"
}
]
}
flutter:
assets:
- assets/data.json
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
// Factory pour convertir un objet JSON en instance de User
factory User.fromJson(Map json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
}
class User {
final int id;
final String name;
final String email;
// Constructeur simple
User({required this.id, required this.name, required this.email});
}
import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;
import 'user.dart'; // Importez la classe User si elle est dans un autre fichier
Future<List<User>> fetchUsers() async {
// Charger le contenu brut du fichier JSON
final String response = await rootBundle.loadString('assets/data/sample.json');
// Décoder le contenu en Map
final Map User.fromJson(json)).toList();
}
import 'dart:convert';
import 'package:flutter/services.dart';
import 'user.dart';
Future> fetchUsers() async {
final String response = await rootBundle.loadString('assets/data/users.json');
final List data = json.decode(response);
return data.map((json) => User.fromJson(json)).toList();
}
import 'package:flutter/material.dart';
import 'user.dart'; // Modèle User
import 'data_service.dart'; // Fichier contenant fetchUsers()
class UsersPage extends StatefulWidget {
@override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State {
late Future<List<User>> _usersFuture;
@override
void initState() {
super.initState();
_usersFuture = fetchUsers(); // Charger les utilisateurs depuis le fichier JSON
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Liste des Utilisateurs'),
),
body: FutureBuilder<List<User>>(
future: _usersFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Erreur : ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('Aucun utilisateur trouvé.'));
} else {
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return Card(
margin: EdgeInsets.all(8.0),
child: ListTile(
title: Text(user.name, style: TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text('Email : ${user.email}'),
),
);
},
);
}
},
),
);
}
}
import 'package:flutter/material.dart';
import 'employes_page.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: EmployesPage(),
));
}
Une
API (Application Programming Interface)
est un ensemble de règles et de protocoles permettant à différentes applications ou systèmes de communiquer entre eux. Dans le contexte de charger des données JSON depuis une API, cela signifie obtenir des données JSON depuis un serveur distant (ou une application web) via des requêtes réseau, souvent grâce au protocole HTTP ou HTTPS.
class User {
final int id;
final String name;
final String email;
User({required this.id, required this.name, required this.email});
// Factory pour convertir un objet JSON en instance de User
factory User.fromJson(Map json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
}
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'user.dart';
Future<List<User>> fetchUsersFromApi() async {
const String apiUrl = 'https://jsonplaceholder.typicode.com/users'; // Exemple d'API
final response = await http.get(Uri.parse(apiUrl));
if (response.statusCode == 200) {
// Décoder la réponse JSON
final List<dynamic> usersJson = json.decode(response.body);
// Convertir chaque élément JSON en un objet User
return usersJson.map((json) => User.fromJson(json)).toList();
} else {
// En cas d'erreur, lever une exception
throw Exception('Erreur lors du chargement des utilisateurs');
}
}
import 'package:flutter/material.dart';
import 'user.dart';
import 'api_service.dart';
class UsersPage extends StatefulWidget {
@override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State {
late Future<List<User>> _usersFuture;
@override
void initState() {
super.initState();
_usersFuture = fetchUsersFromApi();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Liste des Utilisateurs'),
centerTitle: true,
),
body: FutureBuilder<List<User>>(
future: _usersFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Erreur : ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('Aucun utilisateur trouvé.'));
} else {
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
final user = users[index];
return Card(
margin: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
child: ListTile(
leading: CircleAvatar(
child: Text(user.name[0]),
),
title: Text(user.name),
subtitle: Text(user.email),
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Vous avez cliqué sur ${user.name}')),
);
},
),
);
},
);
}
},
),
);
}
}
import 'package:flutter/material.dart';
import 'user.dart';
import 'api_service.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: UsersPage(),
);
}
}
}
class Product {
final int id;
final String name;
final double price;
Product({required this.id, required this.name, required this.price});
factory Product.fromJson(Map json) {
return Product(
id: json['id'],
name: json['name'],
price: json['price'].toDouble(),
);
}
}
List<Product> parseProducts(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Product>((json) => Product.fromJson(json)).toList();
}
import 'package:flutter/material.dart';
import 'api_service.dart';
import 'user.dart';
class UsersPage extends StatefulWidget {
@override
_UsersPageState createState() => _UsersPageState();
}
class _UsersPageState extends State {
late Future<List<User>> _usersFuture;
@override
void initState() {
super.initState();
_usersFuture = fetchUsersFromApi(); // Charger les utilisateurs depuis l'API
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Utilisateurs depuis une API'),
),
body: FutureBuilder<List<User>>(
future: _usersFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Erreur : ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return Center(child: Text('Aucun utilisateur trouvé.'));
} else {
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),
leading: CircleAvatar(
child: Text(user.name[0]), // Affiche la première lettre du nom
),
);
},
);
}
},
),
);
}
}