Implémentation des réseaux Flutter
Table des matières
- Configuration et permissions
- Exécution des requêtes et gestion des réponses
- Analyse en arrière-plan
- Flux de travail : Exécution des opérations réseau
- Exemples
Configuration et permissions
Configurez l'environnement et les permissions spécifiques à la plateforme requises pour l'accès réseau.
- Ajoutez la dépendance du package
httpvia le terminal :flutter pub add http - Importez le package dans vos fichiers Dart :
import 'package:http/http.dart' as http; - Configurez les permissions Android en ajoutant la permission Internet à
android/app/src/main/AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" /> - Configurez les droits macOS en ajoutant la clé client réseau à la fois à
macos/Runner/DebugProfile.entitlementsetmacos/Runner/Release.entitlements:<key>com.apple.security.network.client</key> <true/>
Exécution des requêtes et gestion des réponses
Exécutez les opérations HTTP et mappez les réponses à des objets Dart fortement typés.
- URIs : Analysez toujours les chaînes d'URL en utilisant
Uri.parse('your_url'). - Headers : Injectez les headers d'autorisation et de type de contenu via le paramètre de carte
headers. UtilisezHttpHeaders.authorizationHeaderpour les tokens d'authentification. - Payloads : Pour les requêtes POST et PUT, encodez le corps en utilisant
jsonEncode()depuisdart:convert. - Validation du statut : Évaluez
response.statusCode. Traitez200 OK(GET/PUT/DELETE) et201 CREATED(POST) comme un succès. - Gestion des erreurs : Levez des exceptions explicites pour les codes de statut non-succès. Ne retournez jamais
nullen cas d'échec, car cela empêcheFutureBuilderde déclencher son état d'erreur et provoque des indicateurs de chargement infinis. - Désérialisation : Analysez la chaîne brute en utilisant
jsonDecode(response.body)et mappez-la à un objet Dart personnalisé à l'aide d'un constructeur factory (par exemple,fromJson).
Analyse en arrière-plan
Déléguez l'analyse JSON coûteuse à une Isolate distincte pour éviter les saccades de l'interface utilisateur (chutes d'images).
- Importez
package:flutter/foundation.dart. - Utilisez la fonction
compute()pour exécuter la logique d'analyse dans une isolate de fond. - Assurez-vous que la fonction d'analyse passée à
compute()est une fonction de haut niveau ou une méthode statique, car les closures ou les méthodes d'instance ne peuvent pas être transmises entre les isolates.
Flux de travail : Exécution des opérations réseau
Utilisez la liste de contrôle suivante pour implémenter et valider les opérations réseau.
Progression des tâches :
- [ ] 1. Définissez le modèle Dart fortement typé avec un constructeur factory
fromJson. - [ ] 2. Implémentez la méthode de requête réseau retournant un
Future<Model>. - [ ] 3. Appliquez une logique conditionnelle basée sur le type d'opération :
- Si récupération de données (GET) : Ajoutez les paramètres de requête à l'URI.
- Si mutation de données (POST/PUT) : Définissez
'Content-Type': 'application/json; charset=UTF-8'et attachez le corpsjsonEncode. - Si suppression de données (DELETE) : Retournez une instance de modèle vide en cas de succès (
200 OK).
- [ ] 4. Validez le
statusCodeet levez uneExceptionen cas d'échec. - [ ] 5. Intégrez le
Futuredans l'interface utilisateur en utilisantFutureBuilder. - [ ] 6. Gérez
snapshot.hasData,snapshot.hasError, et par défaut unCircularProgressIndicator. - [ ] 7. Boucle de rétroaction : Exécutez l'application -> déclenchez la requête réseau -> consultez la console pour les exceptions non gérées -> corrigez les erreurs d'analyse ou de permissions.
Exemples
Implémentation haute fidélité : Récupération et analyse en arrière-plan
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
// 1. Fonction d'analyse de haut niveau pour Isolate
List<Photo> parsePhotos(String responseBody) {
final parsed = (jsonDecode(responseBody) as List<Object?>)
.cast<Map<String, Object?>>();
return parsed.map<Photo>(Photo.fromJson).toList();
}
// 2. Exécution réseau avec analyse en arrière-plan
Future<List<Photo>> fetchPhotos() async {
final response = await http.get(
Uri.parse('https://jsonplaceholder.typicode.com/photos'),
headers: {
HttpHeaders.authorizationHeader: 'Bearer your_token_here',
HttpHeaders.acceptHeader: 'application/json',
},
);
if (response.statusCode == 200) {
// Déléguez l'analyse lourde à une isolate de fond
return compute(parsePhotos, response.body);
} else {
throw Exception('Failed to load photos. Status: ${response.statusCode}');
}
}
}
// 3. Modèle fortement typé
class Photo {
final int id;
final String title;
final String thumbnailUrl;
const Photo({
required this.id,
required this.title,
required this.thumbnailUrl,
});
factory Photo.fromJson(Map<String, dynamic> json) {
return Photo(
id: json['id'] as int,
title: json['title'] as String,
thumbnailUrl: json['thumbnailUrl'] as String,
);
}
}
// 4. Intégration de l'interface utilisateur
class PhotoGallery extends StatefulWidget {
const PhotoGallery({super.key});
@override
State<PhotoGallery> createState() => _PhotoGalleryState();
}
class _PhotoGalleryState extends State<PhotoGallery> {
late Future<List<Photo>> _futurePhotos;
@override
void initState() {
super.initState();
// Initialisez Future une seule fois pour éviter la réfétching lors des reconstructions
_futurePhotos = fetchPhotos();
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<Photo>>(
future: _futurePhotos,
builder: (context, snapshot) {
if (snapshot.hasData) {
final photos = snapshot.data!;
return ListView.builder(
itemCount: photos.length,
itemBuilder: (context, index) => ListTile(
leading: Image.network(photos[index].thumbnailUrl),
title: Text(photos[index].title),
),
);
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
// État de chargement par défaut
return const Center(child: CircularProgressIndicator());
},
);
}
}