Flutter调用Moralis API获取NFT时遇空类型转换错误求助
Flutter调用Moralis API获取NFT时遇到Null转String错误的解决方案
错误信息
Unhandled Exception: type 'Null' is not a subtype of type 'String'
报错关联代码段
- Metadata解析逻辑:
final meta = jsonDecode(map?['metadata']); meta_name = meta['name'] ?? ''; meta_image = meta['image'] ?? ''; meta_description = meta['description'] ?? '';
- API响应解析逻辑:
if (response.statusCode == 200) { nfts = jsonDecode(response.body)['result'].map<Nfts>((result) { return Nfts.fromMap(result); }).toList(); }
问题根源
- Metadata字段可能为空:Moralis返回的部分NFT数据中
metadata字段为null,直接传入jsonDecode会导致解码失败,后续访问meta的键值会触发类型错误。 - 类字段定义不匹配API响应:API中
total、cursor为可空值,但Nfts类中定义为非空String;且类中错误定义了result字段(API里的result是数组,对应NFT列表,无需在单个NFT类中声明)。 - 空URL触发NetworkImage错误:若
meta_image为空字符串,NetworkImage会因无效URL报错。
解决方案
1. 修正Nfts类的字段与构造方法
匹配API响应调整字段类型,增加Metadata空值与解码异常处理:
import 'dart:convert'; class Nfts { String? total; late String page; late String page_size; String? cursor; late String token_id; late String token_address; late String amount; late String owner_of; late String token_hash; late String block_number_minted; late String block_number; late String contract_type; late String name; late String symbol; String? token_uri; String? metadata; late String last_token_uri_sync; late String last_metadata_sync; late String minter_address; late String meta_name; late String meta_image; late String meta_description; Nfts({ this.total, required this.page, required this.page_size, this.cursor, required this.token_id, required this.token_address, required this.amount, required this.owner_of, required this.token_hash, required this.block_number_minted, required this.block_number, required this.contract_type, required this.name, required this.symbol, this.token_uri, this.metadata, required this.last_token_uri_sync, required this.last_metadata_sync, required this.minter_address, required this.meta_name, required this.meta_image, required this.meta_description, }); Nfts.fromMap(Map<String, dynamic> map) { total = map['total']?.toString(); page = map['page']?.toString() ?? '1'; page_size = map['page_size']?.toString() ?? '100'; cursor = map['cursor']; token_id = map['token_id'] ?? ''; token_address = map['token_address'] ?? ''; amount = map['amount'] ?? ''; owner_of = map['owner_of'] ?? ''; token_hash = map['token_hash'] ?? ''; block_number_minted = map['block_number_minted'] ?? ''; block_number = map['block_number'] ?? ''; contract_type = map['contract_type'] ?? ''; name = map['name'] ?? ''; symbol = map['symbol'] ?? ''; token_uri = map['token_uri']; metadata = map['metadata']; last_token_uri_sync = map['last_token_uri_sync'] ?? ''; last_metadata_sync = map['last_metadata_sync'] ?? ''; minter_address = map['minter_address'] ?? ''; // 处理metadata为空或解码失败的情况 if (metadata != null && metadata!.isNotEmpty) { try { final meta = jsonDecode(metadata!); meta_name = meta['name'] ?? ''; meta_image = meta['image'] ?? ''; meta_description = meta['description'] ?? ''; } catch (_) { meta_name = ''; meta_image = ''; meta_description = ''; } } else { meta_name = ''; meta_image = ''; meta_description = ''; } } }
2. 优化NftsProviders的API调用逻辑
支持动态传入钱包地址,增加响应空值判断:
import 'package:http/http.dart' as http; import 'dart:convert'; class NftsProviders{ Future<List<Nfts>> getNfts(String walletAddress) async { final Uri uri = Uri.parse('https://deep-index.moralis.io/api/v2/$walletAddress/nft?chain=polygon&format=decimal'); List<Nfts> nfts = []; final response = await http.get(uri, headers: { 'accept': 'application/json', 'X-API-Key' : 'o1g9ywaRjZvZaeaByxhZc7mFOBVVvDJEksU0jeZ8b34fNX03ISTc72fltfsAnuYG' }); if (response.statusCode == 200) { final data = jsonDecode(response.body); if (data['result'] != null && data['result'] is List) { nfts = data['result'].map<Nfts>((result) { return Nfts.fromMap(result); }).toList(); } } else { throw Exception('Failed to load NFT: ${response.statusCode}'); } return nfts; } }
3. 修复UI展示的空值问题
处理NFT图片为空的情况,添加默认占位图:
// NftsScreen的itemBuilder部分修改 itemBuilder: (context, index) { final nft = nfts[index]; return Container( padding: EdgeInsets.all(8.0), child: Column( children: [ CupertinoButton( onPressed: () {}, child: CircleAvatar( radius: 100, backgroundImage: nft.meta_image.isNotEmpty ? NetworkImage(nft.meta_image) : const AssetImage('assets/default_nft.png') as ImageProvider, backgroundColor: Colors.grey[200], ), ), if (nft.meta_name.isNotEmpty) Text(nft.meta_name), ], ), ); },
注:需在项目
assets目录添加default_nft.png,并在pubspec.yaml中配置资源路径。
4. 从Firebase获取钱包地址并调用API
在initNfts方法中传入从Firebase获取的用户钱包地址:
Future initNfts() async { // 替换为实际从Firebase获取钱包地址的逻辑 String walletAddress = await FirebaseAuth.instance.currentUser!.displayName!; nfts = await nftsProvider.getNfts(walletAddress); }
内容的提问来源于stack exchange,提问作者dev cat
相关产品推荐
相关产品推荐

