Home > Software design >  How to parse dynamic JSON with Flutter?
How to parse dynamic JSON with Flutter?

Time:11-05

I do not understand how to parse a JSON file I get from firebase.

This is the format of the JSON file

{
  "water" : {
    "-MnRJkFC3--ZOTmpF1xN" : {
      "milliliters" : 0.14,
      "time" : "16:26:25"
    },
    "-MnRJkZRwZYEInHfSKIY" : {
      "milliliters" : 48.83,
      "time" : "16:26:25"
    },
    "-MnRJksES18hY765rxxq" : {
      "milliliters" : 41.44,
      "time" : "16:26:25"
    },
    "-MnRJlDn6o4RmiGRJS-E" : {
      "milliliters" : 11.37,
      "time" : "16:26:25"
    }
  }
}

This is how I am reading the JSON file

Future loadSalesData() async {
  final String jsonString = await getJsonFromFirebase();
  final dynamic jsonResponse = json.decode(jsonString);
  for (Map<String, dynamic> i in jsonResponse)
    chartData.add(SalesData.fromJson(i));
  }

The getJsonFromFirebase() looks like this:

Future<String> getJsonFromFirebase() async {
  String url =
      "https://emailpassword. . .seio.com/water.json";
  http.Response response = await http.get(Uri.parse(url));
  return response.body;
}

When you click on the link it send you to the JSON file which looks like this

{
    "-Mnbk2ye2P8bfpaQvNaU": {
        "milliliters": 0.0,
        "time": "18:07:00"
    },
    "-Mnbk6wd-wJze8P0JknK": {
        "milliliters": 0.12,
        "time": "18:07:00"
    },
    "-Mnbk7Ek629vgBu-MiLg": {
        "milliliters": 44.91,
        "time": "18:07:00"
    },
    "-Mnbk7bPuzqwsz9d5nm6": {
        "milliliters": 5.43,
        "time": "18:07:00"
    },
    "-Mnbk7v7MADi7YzEbeFI": {
        "milliliters": 24.54,
        "time": "18:07:00"
    },
    "-Mnbk8DGfqswckdsA1qP": {
        "milliliters": 47.58,
        "time": "18:07:00"
    },
    "-Mnbk8Xw2kJPxLrqCl6h": {
        "milliliters": 13.98,
        "time": "18:07:00"
    }
}

I get the Error

_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable'

CodePudding user response:

With the shape of the JSON you are receiving, json.decode will return a Map<String, dynamic> (more specifically an instance of the _InternalLinkedHashMap<String, dynamic> specialisation). This type doesn't implement Iterable, so you can't iterate over it directly with the for-in construct, and this is the exact error you are getting, at run time.

Depending on what you need to construct your SalesData instance, you have two options:

  • iterate over the entries property, if you need the key of each item ("-Mnbk2ye2P8bfpaQvNaU", "-Mnbk6wd-wJze8P0JknK" etc), otherwise
  • iterate over the values property, if you don't

Entries

Iteration:
for (MapEntry<String, dynamic> i in jsonResponse.entries) {
  chartData.add(SalesData.fromJson(i));
}
SalesData.fromJson:
SalesData.fromJson(MapEntry<String, dynamic> data) {
  id = data.key;
  milliliters = data.value['milliliters'];
  time = data.value['time'];
}

Values

Iteration:
for (Map<String, dynamic> i in jsonResponse.values) {
  chartData.add(SalesData.fromJson(i));
}
SalesData.fromJson:
SalesData.fromJson(Map<String, dynamic> data) {
  milliliters = data['milliliters'];
  time = data['time'];
}

Type Inference

Additionally, regardless of how you decide to iterate over the Map instance, you can clean up the code a little taking advantage of Dart's type inference, so (presuming you are iterating over the entries) loadSalesData could become:

Future loadSalesData() async {
  final jsonString = await getJsonFromFirebase();
  final jsonResponse = json.decode(jsonString);

  for (final i in jsonResponse.entries) {
    chartData.add(SalesData.fromJson(i));
  }
}

and getJsonFromFirebase could become:

Future<String> getJsonFromFirebase() async {
  final url = "http://localhost:8080/data.json";
  final response = await http.get(Uri.parse(url));
  return response.body;
}

CodePudding user response:

It seems flutter does not understand that jsonResponse is an iterable because you defined it as dynamic.

Adjust the definition to tell flutter it is a map:

final Map<String, dynamic> jsonResponse = json.decode(jsonString);
  • Related