Sérialisation manuelle de JSON dans Flutter
Sommaire
- Directives fondamentales
- Flux de travail : Implémenter un modèle sérialisable
- Flux de travail : Récupérer et analyser JSON
- Exemples
Directives fondamentales
- Importer
dart:convert: Utiliser la bibliothèque intégrée de Flutterdart:convertpour l'encodage (jsonEncode) et le décodage (jsonDecode) manuels de JSON. - Appliquer la sécurité des types : Toujours caster le résultat
dynamicdejsonDecode()au type attendu, généralementMap<String, dynamic>pour les objets ouList<dynamic>pour les tableaux. - Encapsuler la logique de sérialisation : Définir des classes de modèle simples contenant des propriétés correspondant à la structure JSON. Implémenter un constructeur de fabrique
fromJsonet une méthodetoJsonau sein du modèle. - Gérer l'analyse en arrière-plan : Si l'analyse de grands documents JSON (temps d'exécution > 16 ms), déléguer la logique d'analyse à un isolat séparé en utilisant la fonction
compute()de Flutter pour éviter les ralentissements de l'interface utilisateur. - Lancer des exceptions en cas d'échec : Lors du traitement des réponses HTTP, lancer une exception si le code de statut n'est pas réussi (par exemple, pas 200 OK ou 201 Created). Ne pas retourner
null.
Flux de travail : Implémenter un modèle sérialisable
Utiliser cette liste de contrôle pour implémenter la sérialisation manuelle de JSON pour un modèle de données.
Progression des tâches :
- [ ] Définir la classe de 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 non-concordance de types -> corriger la logique de casting.
- Définir le modèle : Créer une classe avec des propriétés correspondant aux clés JSON.
- Implémenter
fromJson: Extraire les valeurs de laMapet les caster aux types Dart appropriés. Utiliser la correspondance de motifs ou le casting explicite. - Implémenter
toJson: Retourner uneMap<String, dynamic>mappant les propriétés de la classe à leurs clés de chaîne JSON. - Valider : Exécuter des tests unitaires pour garantir que la sécurité des types, l'autocomplétion et la gestion des exceptions au moment de la compilation fonctionnent correctement.
Flux de travail : Récupérer et analyser JSON
Utiliser ce flux de travail 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 ou Isolat).
- [ ] Décoder et mapper le JSON au modèle.
- Exécuter la requête : Utiliser le package
httppour effectuer l'appel réseau. - Valider la réponse :
- Si
response.statusCode == 200(ou 201 pour POST), procéder à l'analyse. - Si le code de statut indique un échec, lancer une
Exception.
- Si
- Déterminer la stratégie d'analyse :
- Si l'analyse d'une petite charge utile (par exemple, un seul objet), analyser de manière synchrone sur le thread principal.
- Si l'analyse d'une grande charge utile (par exemple, un tableau de milliers d'objets), utiliser
compute(parseFunction, response.body)pour analyser dans un isolat en arrière-plan.
- Décoder et mapper : Passer le JSON décodé au constructeur
fromJsonde votre modèle.
Exemples
Implémentation du 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 (petite charge utile)
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 (grande charge utile)
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');
}
}