0

I am trying to parse an API response in a Future:

Future<Map<String, dynamic>> getReading() async {
  const uri = 'https://xxxxxxxxx';
  final response = await http.get(Uri.parse(uri));

  if (response.statusCode == HTTP_OK) {
    var res = jsonDecode(response.body).cast<Map<String, dynamic>>();
    //var hc = res.data;
    return res;
  } else {
    throw Exception('Failed to load Reading summary data.');
  }
}

The above code throws a run time error: NoSuchMethodError.

If I return directly the decoded response.body, it is something like this:

{
    "statusCode": 200,
    "data": {
        "hc": "148",
        "rc": "182"
    }
}

I just need the hc/rc field.

I can't access direclty using res.data.hc (prompting sound null safety issue).

Thanks for your help.

UPDATE

Thakns for all's inputs.

The map returns OK.

Now in the FutureBuilder, I am trying to do something like this:

class _ReadCardState extends State<ReadCard> {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Map<String, dynamic>>(
        future: getReading(),
        builder: (BuildContext context,
            AsyncSnapshot<Map<String, dynamic>> snapshot) {
          if (snapshot.hasData) {
            var res = snapshot.data;
            var hc = res?['hc'] ?? 'n/a';
            print(hc);
            var rc = res?['rc'] ?? '/na';
            print(rc);
            final text = '截止,共评论书籍$hc本,读书笔记$rc篇';

            return Card(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  const ListTile(
                    leading: FaIcon(
                      FontAwesomeIcons.glasses,
                      color: Colors.amber,
                      size: 50,
                    ),
                    title: Text('读书'),
                    subtitle: Text('截止,共评论书籍$hc本,读书笔记$rc篇'),
                  )
                ],
              ),
            );
          } else if (snapshot.hasError) {
            return Center(
              child: Text('Error: ${snapshot.error}'),
            );
          } else {
            return Center(
              child: CircularProgressIndicator(
                strokeWidth: 2.0,
              ),
            );
          }
        });
  }
}

The two print statements correctly prints the numbers. The problem is when I want to insert these two values into a Text widget, it is a compile time error:

{
    "resource": "/d:/My Programs/rsywx/lib/CardBuilder/ReadCard.dart",
    "owner": "_generated_diagnostic_collection_name_#2",
    "code": {
        "value": "const_constructor_param_type_mismatch",
        "target": {
            "$mid": 1,
            "external": "https://dart.dev/diagnostics/const_constructor_param_type_mismatch",
            "path": "/diagnostics/const_constructor_param_type_mismatch",
            "scheme": "https",
            "authority": "dart.dev"
        }
    },
    "severity": 8,
    "message": "A value of type 'Null' can't be assigned to a parameter of type 'String' in a const constructor.\nTry using a subtype, or removing the keyword 'const'.",
    "source": "dart",
    "startLineNumber": 38,
    "startColumn": 36,
    "endLineNumber": 38,
    "endColumn": 59
}

Any further help?

TaylorR
  • 3,746
  • 5
  • 25
  • 42
  • https://stackoverflow.com/a/69277243/7972633 might help you out. – HeIsDying Oct 02 '21 at 03:25
  • If you get data from API refer my answer [here](https://stackoverflow.com/a/68709502/13997210) or [here](https://stackoverflow.com/a/68533647/13997210) or [here](https://stackoverflow.com/a/68594656/13997210) or [here](https://stackoverflow.com/a/69116765/13997210) hope it's helpful to you – Ravindra S. Patil Oct 02 '21 at 06:41
  • @RavindraS.Patil Thanks. Your method shows null safety issue in current flutter. – TaylorR Oct 02 '21 at 07:00

3 Answers3

0

The casting is causing the error, use as. Btw, you don't really need a cast here. Plus, you can't access map items with something like res.data.hc, only if you convert the result into an object. Try this code:

const jsonString =
    '{ "statusCode": 200, "data": {  "hc": "148", "rc": "182"}}';
final jsonDecoded = jsonDecode(jsonString) as Map<String, dynamic>;
print(jsonDecoded["data"]["hc"]);
Peter Koltai
  • 8,296
  • 2
  • 10
  • 20
0

No need to cast. It will work without casting. But if you need to access fields like this res.data.hc then you need to convert the decoded result to custom object Serializing JSON inside model classes.

Future<Map<String, dynamic>> getReading() async {
  const uri = 'https://xxxxxxxxx';
  final response = await http.get(Uri.parse(uri));

  if (response.statusCode == HTTP_OK) {
    var res = jsonDecode(response.body);
    var hc = res["data"]["hc"];
    return res;
  } else {
    throw Exception('Failed to load Reading summary data.');
  }
}
rosh-dev851
  • 534
  • 4
  • 8
0

My bad...

The issue raised from the const keyword on the ListTile. Taking this out, everything is perfectly fine.

TaylorR
  • 3,746
  • 5
  • 25
  • 42