Sérialisation manuelle de JSON en Flutter
Contenu
- Principes fondamentaux
- Workflow : Implémenter un modèle sérialisable
- Workflow : Récupérer et analyser du JSON
- Exemples
Principes fondamentaux
- Importer
dart:convert: Utilisez la bibliothèque intégréedart:convertde Flutter pour l'encodage JSON manuel (jsonEncode) et le décodage (jsonDecode). - Appliquer la sécurité des types : Castez toujours le résultat
dynamicdejsonDecode()vers le type attendu, généralementMap<String, dynamic>pour les objets ouList<dynamic>pour les tableaux. - Encapsuler la logique de sérialisation : Définissez des classes modèle simples contenant des propriétés correspondant à la structure JSON. Implémentez un constructeur factory
fromJsonet une méthodetoJsondans le modèle. - Gérer l'analyse en arrière-plan : Si vous analysez des documents JSON volumineux (temps d'exécution > 16 ms), déportez la logique d'analyse vers un isolate séparé en utilisant la fonction
compute()de Flutter pour éviter le saccadement de l'interface. - Lever des exceptions en cas d'erreur : Lors du traitement des réponses HTTP, levez une exception si le code de statut n'est pas réussi (par exemple, pas 200 OK ou 201 Created). Ne retournez pas
null.
Workflow : Implémenter un modèle sérialisable
Utilisez cette checklist pour implémenter la sérialisation manuelle de JSON pour un modèle de données.
Progression des tâches :
- [ ] Définir la classe modèle simple avec des propriétés
final. - [ ] Implémenter le constructeur
factory Model.fromJson(Map<String, dynamic> json). - [ ] Implémenter la méthode
Map<String, dynamic> toJson(). - [ ] Écrire des tests unitaires pour les deux méthodes de sérialisation.
- [ ] Exécuter le validateur -> examiner les erreurs de type mismatch -> corriger la logique de casting.
- Définir le modèle : Créez une classe avec des propriétés correspondant aux clés JSON.
- Implémenter
fromJson: Extrayez les valeurs de laMapet castez-les vers les types Dart appropriés. Utilisez le pattern matching ou un casting explicite. - Implémenter
toJson: Retournez uneMap<String, dynamic>mappant les propriétés de la classe à leurs clés de chaîne JSON. - Valider : Exécutez les tests unitaires pour vous assurer que la sécurité des types, l'autocomplétion et la gestion des exceptions au moment de la compilation fonctionnent correctement.
Workflow : Récupérer et analyser du JSON
Utilisez ce workflow conditionnel lors de la récupération et de l'analyse de JSON à partir d'une requête réseau.
Progression des tâches :
- [ ] Exécuter la requête HTTP.
- [ ] Valider le code de statut de la réponse.
- [ ] Déterminer la stratégie d'analyse (Synchrone vs. Isolate).
- [ ] Décoder et mapper le JSON vers le modèle.
- Exécuter la requête : Utilisez le package
httppour effectuer l'appel réseau. - Valider la réponse :
- Si
response.statusCode == 200(ou 201 pour POST), procédez à l'analyse. - Si le code de statut indique une erreur, levez une
Exception.
- Si
- Déterminer la stratégie d'analyse :
- Si vous analysez une charge utile petite (par exemple, un seul objet), analysez de manière synchrone sur le thread principal.
- Si vous analysez une charge utile volumineuse (par exemple, un tableau de milliers d'objets), utilisez
compute(parseFunction, response.body)pour analyser dans un isolate en arrière-plan.
- Décoder et mapper : Passez le JSON décodé au constructeur
fromJsonde votre modèle.
Exemples
Implémentation de modèle haute fidélité
import 'dart:convert';
class User {
final int id;
final String name;
final String email;
const User({
required this.id,
required this.name,
required this.email,
});
// Factory constructor for deserialization
factory User.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
'id': int id,
'name': String name,
'email': String email,
} =>
User(
id: id,
name: name,
email: email,
),
_ => throw const FormatException('Failed to load User.'),
};
}
// Method for serialization
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'email': email,
};
}
}
Analyse synchrone (charge utile petite)
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<User> fetchUser(http.Client client, int userId) async {
final response = await client.get(
Uri.parse('https://api.example.com/users/$userId'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Decode returns dynamic, cast to Map<String, dynamic>
final Map<String, dynamic> jsonMap = jsonDecode(response.body) as Map<String, dynamic>;
return User.fromJson(jsonMap);
} else {
throw Exception('Failed to load user');
}
}
Analyse en arrière-plan (charge utile volumineuse)
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
// Top-level function required for compute()
List<User> parseUsers(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<dynamic>).cast<Map<String, dynamic>>();
return parsed.map<User>((json) => User.fromJson(json)).toList();
}
Future<List<User>> fetchUsers(http.Client client) async {
final response = await client.get(
Uri.parse('https://api.example.com/users'),
headers: {'Accept': 'application/json'},
);
if (response.statusCode == 200) {
// Offload expensive parsing to a background isolate
return compute(parseUsers, response.body);
} else {
throw Exception('Failed to load users');
}
}