Home > Net >  flutter: Unhandled Exception: type 'Null' is not a subtype of type 'String'
flutter: Unhandled Exception: type 'Null' is not a subtype of type 'String'

Time:02-04

I tried to use Moralis API to call NFT via wallet address, but got following error.

Unhandled Exception: type 'Null' is not a subtype of type 'String'

These are the code lines that were pointed out as having errors.

final meta = jsonDecode(map?['metadata']);

    meta_name = meta['name'] ?? '';
    meta_image = meta['image'] ?? '';
    meta_description = meta['description'] ?? '';
if (response.statusCode == 200) {
      nfts = jsonDecode(response.body)['result'].map<Nfts>((result) {
        return Nfts.fromMap(result);
      }).toList();
    }

The full code for the first one is below.

import 'dart:convert';

class Nfts {
  late String total;
  late String page;
  late String page_size;
  late String cursor;
  late String result;
  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;
  late String token_uri;
  late 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({
    required this.total,
    required this.page,
    required this.page_size,
    required this.cursor,
    required this.result,
    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,
    required this.token_uri,
    required 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'] ?? '';
    page = map?['page'] ?? '';
    page_size = map?['page_size'] ?? '';
    cursor = map?['cursor'] ?? '';
    result = map?['result'] ?? '';
    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'] ?? '';

    final meta = jsonDecode(map?['metadata']);

    meta_name = meta['name'] ?? '';
    meta_image = meta['image'] ?? '';
    meta_description = meta['description'] ?? '';
  }
}

The full code for the second one is below.

class NftsProviders{
  Uri uri = Uri.parse('https://deep-index.moralis.io/api/v2/(personal metamask wallet address)/nft?chain=polygon&format=decimal');

  Future<List<Nfts>> getNfts() async {
    List<Nfts> nfts = [];

    final response = await http.get(uri, headers: {
      'accept': 'application/json',
      'X-API-Key' : 'o1g9ywaRjZvZaeaByxhZc7mFOBVVvDJEksU0jeZ8b34fNX03ISTc72fltfsAnuYG'
    });

    if (response.statusCode == 200) {
      nfts = jsonDecode(response.body)['result'].map<Nfts>((result) {
        return Nfts.fromMap(result);
      }).toList();
    }
    else {
      throw Exception('Failed to load NFT');
    }

    return nfts;
  }
}

With this API, I tried to create a Gridview.builder.

class NftsScreen extends StatefulWidget {
  @override
  _NftsScreenState createState() {
    return new _NftsScreenState();
  }
}

class _NftsScreenState extends State<NftsScreen> {
  List<Nfts> nfts = [];
  bool isLoading = true;
  NftsProviders nftsProvider = NftsProviders();

  Future initNfts() async {
    nfts = await nftsProvider.getNfts();
  }

  @override
  void initState() {
    super.initState();
    initNfts().then((_) {
      setState(() {
        isLoading = false;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("nfts http"),
      ),
      body: isLoading
          ? Center(
              child: const CircularProgressIndicator(),
            )
          : GridView.builder(
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                  childAspectRatio: 0.5,
                  crossAxisSpacing: 20,
                  mainAxisSpacing: 20),
              itemCount: nfts.length,
              itemBuilder: (context, index) {
                return Container(
                  padding: EdgeInsets.all(8.0),
                  child: Column(
                    children: [
                      // Text(nfts[index].name),
                      // Text(nfts[index].metadata),
                      CupertinoButton(
                          onPressed: () {},
                          // CircleAvatar with NetworkImage(nfts[index].meta_image)
                          // size of 100, 100
                          child: CircleAvatar(
                            radius: 100,
                            backgroundImage: NetworkImage(nfts[index].meta_image,),
                          )
                      )
                    ],
                  ),
                );
              }),
    );
  }
}

I want to request NFT information according to the user's wallet address called from Firebase. Thanks in advance.

  • This is part of the api call response.
{
  "total": null,
  "page": 1,
  "page_size": 100,
  "cursor": null,
  "result": [
    {
      "token_address": "0x53a0018f919bde9c254bda697966c5f448ffddcb",
      "token_id": "46388765668907266497641806581710410401632846941109288029645926940148068689172",
      "owner_of": "0xe3281571a136c11cc66d225902d494d29aaf7cb9",
      "block_number": "30362645",
      "block_number_minted": "30362645",
      "token_hash": "8b025de30055bd161b2774da64fc283a",
      "amount": "1",
      "contract_type": "ERC721",
      "name": "EDNS",
      "symbol": "EDNS",
      "token_uri": "https://api.edns.domains/metadata/0x53a0018f919bde9c254bda697966c5f448ffddcb/46388765668907266497641806581710410401632846941109288029645926940148068689172/metadata.json",
      "metadata": "{\"name\":\"goyangtwo.meta\",\"description\":\"Domain goyangtwo.meta from EDNS Domains\",\"image\":\"https://api.edns.domains/metadata/0x53a0018f919bde9C254bda697966C5f448ffDDcB/46388765668907266497641806581710410401632846941109288029645926940148068689172/image.svg\",\"attributes\":[{\"trait_type\":\"TLD\",\"value\":\"meta\"}]}",
      "last_token_uri_sync": "2022-12-06T14:08:39.924Z",
      "last_metadata_sync": "2022-12-06T14:08:44.789Z",
      "minter_address": "0x805ec22fca66eca02e244689b47fc2f180a94f01"
    }
  ],
  "status": "SYNCED"
}

CodePudding user response:

can you share the response of the api call, most probably there will be a typo in the JSON decoding

meta_name = meta['name'] ?? '';
meta_image = meta['image'] ?? '';
meta_description = meta['description'] ?? '';

try quicktype.io to generate response models

CodePudding user response:

What's the source of Nfts? Do you not have accidently defined a field like cursor or total as String instead of String? Otherwise, please provide the code for Nfts as it might have fields of type String without defaults that are not present in the json, causing the Nfts.fromMap(result); to fail.

As a general tip, it is wise to NOT assume that this will always succeed. In case it fails, then i.e. return null instead of crashing your app.

  • Related