使用 GET 方法从 API 获取数据

问题描述 投票:0回答:1

尝试使用 GET 方法从 API 获取数据,但一直显示此错误:`

“错误:类型‘Null’不是类型‘Map’的子类型 类型转换”

`为什么?我正在使用 json_serialized 和 json_annotation dart 包,如下面的代码所示...它不断返回如图所示的错误。

// This is my class for fetching the data...
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:big_shelf/screens/models/models.dart';

class MyProfileApiServices {
  final String myProfileUrl = 'https://bigshelf-node-dev.onrender.com/api/v1/users/my-profile';

  Future<UserModel> fetchUserData() async {
    final response = await http.get(Uri.parse(myProfileUrl));
    if (response.statusCode == 200) {
      final jsonResponse = jsonDecode(response.body);
      final userData = UserModel.fromJson(jsonResponse);
      debugPrint('$userData');
      return userData;
    } else {
      debugPrint('Failed to load data');
      throw Exception('Failed to load user data');
    }
  }
}


// The below is where I want to display the data that has been fetched...
import 'widget.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../services/users/users_services.dart';
import 'package:big_shelf/screens/models/models.dart';
import 'package:big_shelf/screens/common/widget.dart';

class MyShelf extends StatefulWidget {
  const MyShelf({super.key});

  @override
  State<MyShelf> createState() => _MyShelfState();
}

class _MyShelfState extends State<MyShelf> {
  late Future<UserModel> futureUser;

  @override
  void initState() {
    super.initState();
    futureUser = MyProfileApiServices().fetchUserData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'My Shelf',
          style: TextStyle(
            fontWeight: FontWeight.bold,
            fontSize: 16,
            fontFamily: 'Playfair',
          ),
        ),
        actions: [
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 8.0),
            child: Row(
              children: [
                IconButton(
                  onPressed: () {
                    GoRouter.of(context).go('${CustomNavigationHelper.myShelfPath}/${CustomNavigationHelper.settingsPath}');
                  },
                  icon: SvgPicture.asset(
                    'assets/icons/Settings.svg',
                    colorFilter: ColorFilter.mode(
                      Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black,
                      BlendMode.srcIn,
                    ),
                  ),
                ),
                InkWell(
                  onTap: () => GoRouter.of(context).go('${CustomNavigationHelper.myShelfPath}/${CustomNavigationHelper.notificationPath}'),
                  child: Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: Stack(
                      alignment: AlignmentDirectional.topEnd,
                      children: [
                        SvgPicture.asset(
                          width: 25,
                          height: 23,
                          'assets/icons/Bell.svg',
                          colorFilter: ColorFilter.mode(
                            Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black,
                            BlendMode.srcIn,
                          ),
                        ),
                        Container(
                          padding: const EdgeInsets.all(4),
                          decoration: BoxDecoration(
                            color: Theme.of(context).primaryColor,
                            shape: BoxShape.circle,
                          ),
                          child: const Text(
                            '9',
                            style: TextStyle(
                              fontSize: 10.0,
                              color: Colors.black,
                              fontWeight: FontWeight.bold,
                            ),
                            textAlign: TextAlign.center,
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
      body: FutureBuilder<UserModel>(
        future: futureUser,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            debugPrint('Error: ${snapshot.error}');
            return Center(child: Text('Error: ${snapshot.error}'));
          } else if (snapshot.hasData) {
            final user = snapshot.data!.data.user;
            return SingleChildScrollView(
              child: Column(
                children: [
                  Container(
                    alignment: Alignment.center,
                    padding: const EdgeInsets.fromLTRB(0, 20, 0, 10),
                    color: Colors.grey.withOpacity(0.1),
                    child: Column(
                      children: [
                        CircleAvatar(
                          radius: 50.0,
                          backgroundColor: Colors.grey[200],
                          backgroundImage: const AssetImage('assets/images/Profile icon.png'),
                        ),
                        const SizedBox(height: 10),
                        Text(
                          user.username,
                          style: const TextStyle(
                            fontSize: 25.0,
                            fontWeight: FontWeight.bold,
                            fontFamily: 'Playfair',
                          ),
                        ),
                        Text(
                          '${snapshot.data!.data.followersCount} followers, ${snapshot.data!.data.followingCount} following',
                          style: const TextStyle(
                            fontSize: 12.0,
                            fontWeight: FontWeight.w300,
                            fontFamily: 'Satoshi',
                          ),
                        ),
                        const SizedBox(height: 15),
                        Padding(
                          padding: const EdgeInsets.symmetric(horizontal: 80),
                          child: ElevatedButton(
                            onPressed: () => GoRouter.of(context).go('${CustomNavigationHelper.myShelfPath}/${CustomNavigationHelper.createCollectionPath}'),
                            style: ElevatedButton.styleFrom(
                              elevation: 0,
                              backgroundColor: Colors.transparent,
                              shape: RoundedRectangleBorder(
                                side: BorderSide(
                                  color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black,
                                ),
                                borderRadius: BorderRadius.circular(10),
                              ),
                              minimumSize: const Size(30, 60),
                            ),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Icon(
                                  Icons.add,
                                  color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black,
                                ),
                                const SizedBox(width: 10),
                                Text(
                                  'Create a collection',
                                  style: TextStyle(
                                    fontWeight: FontWeight.w500,
                                    fontSize: 15.0,
                                    color: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black,
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                  const SizedBox(height: 10),
                  Container(
                    alignment: Alignment.centerLeft,
                    padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
                    child: const Text(
                      'Your Shelf',
                      style: TextStyle(
                        fontFamily: 'Satoshi',
                        fontSize: 17.0,
                        fontWeight: FontWeight.bold,
                      ),
                      textAlign: TextAlign.left,
                    ),
                  ),
                  const SizedBox(height: 10),
                  DefaultTabController(
                    length: 3,
                    child: Column(
                      children: [
                        Container(
                          padding: const EdgeInsets.all(5),
                          margin: const EdgeInsets.fromLTRB(15, 0, 15, 0),
                          decoration: BoxDecoration(
                            borderRadius: const BorderRadius.all(Radius.circular(10)),
                            color: Colors.grey.withOpacity(0.1),
                          ),
                          child: TabBar(
                            indicatorSize: TabBarIndicatorSize.tab,
                            dividerColor: Colors.transparent,
                            indicatorColor: Theme.of(context).brightness == Brightness.dark ? Colors.white : Colors.black,
                            indicator: const BoxDecoration(
                              borderRadius: BorderRadius.all(Radius.circular(10)),
                              color: Colors.white,
                            ),
                            tabs: [
                              Tab(
                                child: Text(
                                  'Collections',
                                  style: TextStyle(
                                    fontWeight: FontWeight.w700,
                                    fontSize: 12.0,
                                    color: Theme.of(context).brightness == Brightness.dark ? Colors.grey : Colors.black,
                                  ),
                                ),
                              ),
                              Tab(
                                child: Text(
                                  'Followers',
                                  style: TextStyle(
                                    fontWeight: FontWeight.w700,
                                    fontSize: 12.0,
                                    color: Theme.of(context).brightness == Brightness.dark ? Colors.grey : Colors.black,
                                  ),
                                ),
                              ),
                              Tab(
                                child: Text(
                                  'Following',
                                  style: TextStyle(
                                    fontWeight: FontWeight.w700,
                                    fontSize: 12.0,
                                    color: Theme.of(context).brightness == Brightness.dark ? Colors.grey : Colors.black,
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ),
                        SizedBox(
                          height: MediaQuery.of(context).size.height * 0.8,
                          child: const TabBarView(
                            children: [
                              CollectionsMyShelf(),
                              FollowersMyShelf(),
                              FollowingMyShelf(),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            );
          } else {
            return const Center(child: Text('No data found'));
          }
        },
      ),
    );
  }
}

import 'package:json_annotation/json_annotation.dart';

part 'user_model.g.dart';

@JsonSerializable(explicitToJson: true)
class UserModel {
  final String status;
  final UserData data;

  UserModel({
    required this.status,
    required this.data,
  });

  factory UserModel.fromJson(Map<String, dynamic> json) => _$UserModelFromJson(json);
  Map<String, dynamic> toJson() => _$UserModelToJson(this);
}

@JsonSerializable(explicitToJson: true)
class UserData {
  final User user;
  final int followersCount;
  final int followingCount;

  UserData({
    required this.user,
    required this.followersCount,
    required this.followingCount,
  });

  factory UserData.fromJson(Map<String, dynamic> json) => _$UserDataFromJson(json);
  Map<String, dynamic> toJson() => _$UserDataToJson(this);
}

@JsonSerializable(explicitToJson: true)
class User {
  @JsonKey(name: '_id')
  final String id;
  final String name;
  final String username;
  final String email;
  final String role;
  final List<String> savedCollection;
  final List<dynamic> cart;
  final List<dynamic> address;
  final int v;
  final String bankName;
  final String accountName;
  final bool activeAffiliate;
  final int redeemable;
  final int redeemed;
  final DateTime updatedAffiliateAt;

  User({
    required this.id,
    required this.name,
    required this.username,
    required this.email,
    required this.role,
    required this.savedCollection,
    required this.cart,
    required this.address,
    required this.v,
    required this.bankName,
    required this.accountName,
    required this.activeAffiliate,
    required this.redeemable,
    required this.redeemed,
    required this.updatedAffiliateAt,
  });

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}



// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'user_model.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel(
      status: json['status'] as String,
      data: UserData.fromJson(json['data'] as Map<String, dynamic>),
    );

Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
      'status': instance.status,
      'data': instance.data.toJson(),
    };

UserData _$UserDataFromJson(Map<String, dynamic> json) => UserData(
      user: User.fromJson(json['user'] as Map<String, dynamic>),
      followersCount: (json['followersCount'] as num).toInt(),
      followingCount: (json['followingCount'] as num).toInt(),
    );

Map<String, dynamic> _$UserDataToJson(UserData instance) => <String, dynamic>{
      'user': instance.user.toJson(),
      'followersCount': instance.followersCount,
      'followingCount': instance.followingCount,
    };

User _$UserFromJson(Map<String, dynamic> json) => User(
      id: json['_id'] as String,
      name: json['name'] as String,
      username: json['username'] as String,
      email: json['email'] as String,
      role: json['role'] as String,
      savedCollection: (json['savedCollection'] as List<dynamic>)
          .map((e) => e as String)
          .toList(),
      cart: json['cart'] as List<dynamic>,
      address: json['address'] as List<dynamic>,
      v: (json['v'] as num).toInt(),
      bankName: json['bankName'] as String,
      accountName: json['accountName'] as String,
      activeAffiliate: json['activeAffiliate'] as bool,
      redeemable: (json['redeemable'] as num).toInt(),
      redeemed: (json['redeemed'] as num).toInt(),
      updatedAffiliateAt: DateTime.parse(json['updatedAffiliateAt'] as String),
    );

Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
      '_id': instance.id,
      'name': instance.name,
      'username': instance.username,
      'email': instance.email,
      'role': instance.role,
      'savedCollection': instance.savedCollection,
      'cart': instance.cart,
      'address': instance.address,
      'v': instance.v,
      'bankName': instance.bankName,
      'accountName': instance.accountName,
      'activeAffiliate': instance.activeAffiliate,
      'redeemable': instance.redeemable,
      'redeemed': instance.redeemed,
      'updatedAffiliateAt': instance.updatedAffiliateAt.toIso8601String(),
    };

flutter dart
1个回答
0
投票
class UserModel {
  final String status;
  final UserData data;
error from: 
UserModel({
    required this.status,
    required this.data,
  });

  factory UserModel.fromJson(Map<String, dynamic> json) => _$UserModelFromJson(json);
  Map<String, dynamic> toJson() => _$UserModelToJson(this);
}

此处,空值从 API 传入此模型中的 Map 类型的某些字段。只需检查可为空的模型字段

© www.soinside.com 2019 - 2024. All rights reserved.