Issue
I want to deserialise an array of JSON objects. I followed this tutorial from Flutter documentation. The thing is, this array is nested inside an other object, and looks like this:
{
"result":
{
"array":
[
{
"id": 0,
"name": "here goes the string"
},
{
"id": 1,
"name": "another one here"
} ...
I've been following this official tutorial, and I got stuck with an error:
I/flutter (28639): AsyncSnapshot<List>(ConnectionState.done, null, Exception: NoSuchMethodError: Class '_InternalLinkedHashMap<String, dynamic>' has no instance method 'cast' with matching arguments.
I/flutter (28639): Receiver: _LinkedHashMap len:2
I/flutter (28639): Tried calling: cast<Map<String, dynamic>>()
I/flutter (28639): Found: cast<Y0, Y1>() => Map<Y0, Y1>, #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:68:5)
I'd expect that I referenced poorly .result.array[]
of that deserialised JSON Map<String, dynamic>
thing, though the error shows up one line earlier, and I have completely no idea what's causing that. What might be the reason of this exception, and am I referencing to array in a good way?
My app basically looks like this (I've marked line in which exception is thrown by an arrow (→):
/* [...] */
Future<List<Models.Degree>> fetchDegrees(http.Client client) async
{
final response = await client
.get(Uri.parse("api uri here"));
// Using the compute function to run in a separate isolate.
return compute(parseDegrees, response.body);
}
List<Models.Degree> parseDegrees(String responseBody)
{
→ final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed['result']['array'].map<Models.Degree>((json) => Models.Degree.fromJson(json)).toList();
}
/* [...] */
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: FutureBuilder<List<Models.Degree>>(
future: fetchDegrees(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) {
print(snapshot.toString());
return const Center(
child: Text('An error has occurred!'),
);
} else if (snapshot.hasData) {
return DegreesList(degrees: snapshot.data!);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
}
class DegreesList extends StatelessWidget {
const DegreesList({Key? key, required this.degrees}) : super(key: key);
final List<Models.Degree> degrees;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: degrees.length,
itemBuilder: (context, index) {
return Text(degrees[index].name);
},
);
}
}
Solution
In that tutorial the response body is:
[
{
"albumId": 100,
"id": 4999,
"title": "in voluptate sit officia non nesciunt quis",
"url": "https://via.placeholder.com/600/1b9d08",
"thumbnailUrl": "https://via.placeholder.com/150/1b9d08"
},
{
"albumId": 100,
"id": 5000,
"title": "error quasi sunt cupiditate voluptate ea odit beatae",
"url": "https://via.placeholder.com/600/6dd9cb",
"thumbnailUrl": "https://via.placeholder.com/150/6dd9cb"
}
]
The jsonDecode
method returns dynamic
.
In this case the type is List<dynamic>
. List has a method cast
https://api.dart.dev/stable/2.14.4/dart-core/List/cast.html. So It works fine.
However in your case:
{
"result": {
"array": [
{
"id": 0,
"name": "here goes the string"
},
{
"id": 1,
"name": "another one here"
}
]
}
}
jsonDecode returns _InternalLinkedHashMap and this doesn't have a cast
method, so it throws an exception.
You have many options, just to mention:
Just delete the .cast<Map<String, dynamic>>()
and it will work just fine.
You don't have to cast responseBody
in order to use it because the "array" json key will have the type of List<dynamic>
at the end, so you can use the map
method without a problem.
But if you want to cast that anyways, you can use
final parsed = Map<String, dynamic>.from(jsonDecode(responseBody));
Answered By - Juan Carlos Ramón Condezo
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.