2
votes

I am currently building a flutter app where I want to calculate the distance between some objects and am using the Google Distance Matrix API to do so. I am having trouble parsing the json using Dart. All I want ultimately is a list of the distances from the json results so that I can index them and apply them to the data in my app.

The json results look like this:

{
   "destination_addresses" : [
      "destination address",
      "destination address"
   ],
   "origin_addresses" : [ "Origin addresses here" ],
   "rows" : [
      {
         "elements" : [
            {
               "distance" : {
                  "text" : "4.3 mi",
                  "value" : 6998
               },
               "duration" : {
                  "text" : "14 mins",
                  "value" : 848
               },
               "status" : "OK"
            },
            {
               "distance" : {
                  "text" : "6.7 mi",
                  "value" : 10728
               },
               "duration" : {
                  "text" : "22 mins",
                  "value" : 1327
               },
               "status" : "OK"
            }
         ]
      }
   ],
   "status" : "OK"
}

I ultimately would like to end up with a list (in dart) that is just a list of the distance "text" values within the elements array but I am having trouble getting this to return. I have tried creating a class and mapping the json results to this but unsuccesfully as I am not very good at parsing json so any advice on how to end up with this list would be gratefully received!

I have tried this code to parse the json but am really struggling to make it work and then apply it:

class Topleveladd {
  final String elements;

  Topleveladd({this.elements});

  factory Topleveladd.fromJson(Map<String, dynamic> parsedJson) {
    return Topleveladd(elements: parsedJson['rows']);
  }
}

class Elements {
  List<Distance> distanceslist;

  Elements({this.distanceslist});

  factory Elements.fromJson(Map<String, dynamic> parsedJson) {
    var list = parsedJson['elements'] as List;
    print(list.runtimeType); //returns List<dynamic>
    List<Distance> distancesList =
        list.map((i) => Distance.fromJson(i)).toList();
    return Elements(distanceslist: distancesList);
  }
}

class Distance {
  String text;
  Distance({this.text});

  factory Distance.fromJson(Map<String, dynamic> parsedJson) {
    return new Distance(
      text: parsedJson['distance'],
    );
  }
}
1
I'd recommend this article which goes through how to parse complex JSON within Flutter.SnakeyHips
This is exactly the article I have been using to try and resolve this however I'm struggling, my code has been added above. Thank you!Duncan Roberts
Yeah even with the article it can be tricky. I'll give it a go tomorrow :)SnakeyHips
Thanks so much that would be amazing help!Duncan Roberts

1 Answers

8
votes

Okay this is it working with me accessing the JSON you've given as an asset so you'll probably have to change the loadData method for it to fit your needs.

DistanceMatrix class:

import 'dart:convert';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;

class DistanceMatrix {
  final List<String> destinations;
  final List<String> origins;
  final List<Element> elements;
  final String status;

  DistanceMatrix({this.destinations, this.origins, this.elements, this.status});

  factory DistanceMatrix.fromJson(Map<String, dynamic> json) {
    var destinationsJson = json['destination_addresses'];
    var originsJson = json['origin_addresses'];
    var rowsJson = json['rows'][0]['elements'] as List;

    return DistanceMatrix(
        destinations: destinationsJson.cast<String>(),
        origins: originsJson.cast<String>(),
        elements: rowsJson.map((i) => new Element.fromJson(i)).toList(),
        status: json['status']);
  }

  static Future<DistanceMatrix> loadData() async {
    DistanceMatrix distanceMatrix;
    try{
          String jsonData = await rootBundle.loadString('assets/data.json');
    distanceMatrix = new DistanceMatrix.fromJson(json.decode(jsonData));
    } catch (e){
      print(e);
    }
    return distanceMatrix;
  }
}

class Element {
  final Distance distance;
  final Duration duration;
  final String status;

  Element({this.distance, this.duration, this.status});

  factory Element.fromJson(Map<String, dynamic> json) {
    return Element(
        distance: new Distance.fromJson(json['distance']),
        duration: new Duration.fromJson(json['duration']),
        status: json['status']);
  }
}

class Distance {
  final String text;
  final int value;

  Distance({this.text, this.value});

  factory Distance.fromJson(Map<String, dynamic> json) {
    return new Distance(text: json['text'], value: json['value']);
  }
}

class Duration {
  final String text;
  final int value;

  Duration({this.text, this.value});

  factory Duration.fromJson(Map<String, dynamic> json) {
    return new Duration(text: json['text'], value: json['value']);
  }
}

Main.dart which uses ListView.builder to display the distances text and values as a ListTile:

import 'package:flutter/material.dart';
import 'package:hello_world/distance_matrix.dart';

void main() async {
  runApp(new MyApp(
    distanceMatrix: await DistanceMatrix.loadData(),
  ));
}

class MyApp extends StatefulWidget {
  final DistanceMatrix distanceMatrix;

  @override
  _MyAppState createState() => new _MyAppState();

  MyApp({this.distanceMatrix});
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text("Home"),
            ),
            body: Material(
                child: ListView.builder(
                itemCount: widget.distanceMatrix.elements.length,
                itemBuilder: (context, index){
                  return ListTile(
                    title: Text(widget.distanceMatrix.elements[index].distance.text),
                    subtitle: Text(widget.distanceMatrix.elements[index].distance.value.toString()),
                  );
                },
              )
            )));
  }
}

Image to show what you should get:

enter image description here