Menu
CoddyTech

Hàm khởi tạo fromJson

Thuộc phần Dữ liệu và mạng trong hành trình Flutter của Coddy. Bài học 17 trên 27.

Đọc user['name'] as String trên khắp các màn hình sẽ khiến code trở nên rối rắm, và chỉ một lỗi chính tả trong khóa cũng làm hỏng mọi thứ. Cách khắc phục thường dùng là tạo một lớp cho dữ liệu, với một hàm khởi tạo biết cách xử lý JSON. Hàm này có tên là 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 là một hàm khởi tạo có tên, một cách khác để tạo User. Từ factory cho phép hàm khởi tạo chạy code và return đối tượng mà nó tạo ra. Hàm khởi tạo thông thường không thể return bất cứ thứ gì.

Giờ đây, JSON được đọc ở một nơi duy nhất. Phần còn lại của ứng dụng nhận được một User thực sự, trong đó user.name là một String và lỗi chính tả sẽ gây ra lỗi biên dịch thay vì null:

final body = await fetch('/user');
return User.fromJson(jsonDecode(body));

Hầu như mọi ứng dụng giao tiếp với máy chủ đều có một fromJson cho mỗi loại dữ liệu mà nó nhận được.

challenge icon

Thử thách

Khó

Hồ sơ hiển thị Unknown: loadUser bỏ qua JSON. Thêm cho User một factory User.fromJson(Map<String, dynamic> json) để đọc name, email và age, rồi sửa loadUser để trả về User.fromJson(jsonDecode(body)). Nhập dart:convert.

Tự làm thử

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;
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Dữ liệu và mạng

Tự luyện tập: Trình biên dịch Flutter online