尝试使用 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(),
};
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 类型的某些字段。只需检查可为空的模型字段