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?
CodePudding user response:
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"]);
CodePudding user response:
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.');
}
}
CodePudding user response:
My bad...
The issue raised from the const
keyword on the ListTile
. Taking this out, everything is perfectly fine.