Ein fromJson-Konstruktor
Teil des Abschnitts Daten und Netzwerk der Flutter-Journey von Coddy. Lektion 17 von 27.
Wenn du auf deinen Bildschirmen überall user['name'] as String liest, wird es unübersichtlich, und ein einziger Tippfehler in einem Schlüssel führt zu einem Fehler. Die übliche Lösung ist eine Klasse für die Daten mit einem Konstruktor, der das JSON kennt. Er heißt fromJson:
class User {
User({required this.name, required this.age});
final String name;
final int age;
factory User.fromJson(Map<String, dynamic> json) {
return User(
name: json['name'] as String,
age: json['age'] as int,
);
}
}User.fromJson ist ein benannter Konstruktor, eine zweite Möglichkeit, ein User-Objekt zu erstellen. Das Wort factory ermöglicht es einem Konstruktor, Code auszuführen und das erstellte Objekt mit return zurückzugeben. Ein einfacher Konstruktor kann nichts mit return zurückgeben.
Jetzt wird das JSON an einer Stelle eingelesen. Der Rest der App erhält ein echtes User-Objekt, bei dem user.name ein String ist und ein Tippfehler zu einem Kompilierungsfehler statt zu null führt:
final body = await fetch('/user');
return User.fromJson(jsonDecode(body));Fast jede App, die mit einem Server kommuniziert, hat für jede Art von Daten, die sie empfängt, eine fromJson-Methode.
Aufgabe
SchwerIm Profil steht Unknown: loadUser ignoriert das JSON. Gib User eine factory User.fromJson(Map<String, dynamic> json), die name, email und age ausliest, und lasse loadUser User.fromJson(jsonDecode(body)) zurückgeben. Importiere dart:convert.
Probier es selbst
import 'package:flutter/material.dart';
import 'api.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: ProfileScreen(),
);
}
}
class ProfileScreen extends StatefulWidget {
const ProfileScreen({super.key});
@override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
late Future<User> _user;
@override
void initState() {
super.initState();
_user = loadUser();
}
Future<User> loadUser() async {
final body = await fetch('/user');
print(body);
return User(name: 'Unknown', email: 'unknown', age: 0);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Profile')),
body: Center(
child: FutureBuilder<User>(
future: _user,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Could not load: ${snapshot.error}');
}
if (snapshot.hasData) {
final user = snapshot.data!;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
user.name,
style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(user.email, style: const TextStyle(fontSize: 18)),
const SizedBox(height: 8),
Text('${user.age} years old'),
],
);
}
return const CircularProgressIndicator();
},
),
),
);
}
}
class User {
User({required this.name, required this.email, required this.age});
final String name;
final String email;
final int age;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Daten und Netzwerk
2Ladebildschirme
Ein Spinner während des LadensFutureBuilder kennenlernenEinmalig in initState ladenDaten per Button neu ladenZum Aktualisieren nach unten ziehen5Datumsangaben und Preise
Datumsangaben mit DateFormatUhrzeiten mit DateFormatPreise mit NumberFormatÜbe selbstständig: Online-Flutter-Compiler