Encoding / decoding complex Json in Flutter

5,096

Solution 1

There's a very good article about how to parse complex JSON in Flutter. Here's a quick summary...

Simple Stuff:

{
  "id":"487349",
  "name":"Pooja Bhaumik",
  "score" : 1000
}

becomes...

class Student{
  String studentId;
  String studentName;
  int studentScores;

  Student({
    this.studentId,
    this.studentName,
    this.studentScores
 });

  factory Student.fromJson(Map<String, dynamic> parsedJson){
    return Student(
      studentId: parsedJson['id'],
      studentName : parsedJson['name'],
      studentScores : parsedJson ['score']
    );
  }

}

You create a new Student object like Student.fromJson(your_parsed_json).

Sub-objects work in a similar way. For each object inside the parent object you make a new Dart object, each with it's own parser for fromJson. Then inside the parent factory you call that fromJson method (like so)... This also works for lists of objects.

  factory Student.fromJson(Map<String, dynamic> parsedJson){
    return Student(
      studentId: parsedJson['id'],
      studentName : parsedJson['name'],
      studentScores : Teacher.fromJson(parsedJson['teacher'])
  );

Solution 2

There was no question in your question, but I assume the question is:

My Json code is not working - How do I efficiently parse and encode complex json objects in my flutter program.

For complex JSON you may want to consider using code generation to reduce the boiler plate you have to write. The flutter page has a good example using JsonSerializable. Here the basic instructions for your example:

  1. Add dependencies to pubspec.yaml and run flutter pub get in the command line:
    dependencies:        
        json_annotation: ^1.2.0

    dev_dependencies:       
        build_runner: ^1.0.0 
        json_serializable: ^1.5.1
  1. Create the basic Object model (similar to what you have done). Except for the following differences:

    1. You don't have a List of Status for the field statuss, but a single Status object.
    2. Don't use private fields.
  2. To enable json boiler plate code generation do the following three steps:

    1. add the json-annotations to each class,
    2. add a factory .fromJson method on each class and
    3. add a .toJson method on each class:
    @JsonSerializable()
    class Base {
      List<Device> devices;
      Base({this.devices});
      factory Base.fromJson(Map<String, dynamic> json) => _$BaseFromJson(json);     
      Map<String, dynamic> toJson() => _$BaseToJson(this); 
    }

    @JsonSerializable()
    class Device {
      String device_desc,device_title,image_path;
      int status_id;
      List<function> functions;
      Status statuss ;
      Device(this.device_desc, this.device_title, this.image_path,
          this.status_id, this.functions, this.statuss);
      factory Device.fromJson(Map<String, dynamic> json) => _$DeviceFromJson(json);       
      Map<String, dynamic> toJson() => _$DeviceToJson(this); 
    }

    @JsonSerializable()
    class Status {
      String status_desc, status_title;
      Status(this.status_desc, this.status_title);
      factory Status.fromJson(Map<String, dynamic> json) => _$StatusFromJson(json);   
      Map<String, dynamic> toJson() => _$StatusToJson(this); 
    }

    @JsonSerializable()
    class function {
      String function_desc, function_title;
      int device_id, status;
      function(this.function_desc, this.function_title, this.device_id,
          this.status);
      factory function.fromJson(Map<String, dynamic> json) => _$functionFromJson(json);  
      Map<String, dynamic> toJson() => _$functionToJson(this);       
    }
  1. Run the command line to start code generation in the project root folder:
    flutter packages pub run build_runner watch
  1. Now an additional source file appears with your generated boiler plate code. Add this file to your own source file using the part keyword, for example if your source file is main.dart add the following line:
    part 'main.g.dart';

And you are done - This is all you need to test your encoding / decoding. For example with the following code:

    import 'dart:convert';
    void main() => (){
      var jsonExample = '{"devices": [{"device_desc": "cooler", "device_title": "cooler", "functions": [{"device_id": 1, "function_desc": "pomp", "function_title": "pomp", "status": 1}, {"device_id": 1, "function_desc": "less", "function_title": "less", "status": 1}, {"device_id": 1, "function_desc": "up", "function_title": "up", "status": 1}], "image_path": "fdfdfsf", "status_id": 1, "statuss": {"status_desc": "device is on", "status_title": "on"}}, {"device_desc": "panke", "device_title": "panke", "functions": [{"device_id": 2, "function_desc": "less", "function_title": "pomp", "status": 2}, {"device_id": 2, "function_desc": "less", "function_title": "less", "status": 2}], "image_path": "vfx", "status_id": 2, "statuss": {"status_desc": "device is off", "status_title": "off"}}]}';

      Map base_example = json.decode(jsonExample);
      Base base_example_parsed = Base.fromJson(base_example);
      var numberDevices = base_example_parsed.devices.length;
      var numberFuncs = base_example_parsed.devices[0].functions.length;
      print('$base_example_parsed has $numberDevices devices and the first device has $numberFuncs functions');

      var base_example_encoded_again = json.encode(base_example_parsed);
      print('$base_example_encoded_again');
    };

For more information please refer to: 1. the official example. 2. this blog.

Share:
5,096
ElhamKeshavarz
Author by

ElhamKeshavarz

Updated on December 07, 2022

Comments

  • ElhamKeshavarz
    ElhamKeshavarz over 1 year

    I am going to use a real json. First of all, I should run the project that is written in Flask, then use the local host to achieve data. Here is the real Json I`m using

    {
       "devices":[
          {
             "device_desc":"cooler",
             "device_title":"cooler",
             "functions":[
                {
                   "device_id":1,
                   "function_desc":"pomp",
                   "function_title":"pomp",
                   "status":1
                },
                {
                   "device_id":1,
                   "function_desc":"less",
                   "function_title":"less",
                   "status":1
                },
                {
                   "device_id":1,
                   "function_desc":"up",
                   "function_title":"up",
                   "status":1
                }
             ],
             "image_path":"fdfdfsf",
             "status_id":1,
             "statuss":{
                "status_desc":"device is on",
                "status_title":"on"
             }
          },
          {
             "device_desc":"panke",
             "device_title":"panke",
             "functions":[
                {
                   "device_id":2,
                   "function_desc":"less",
                   "function_title":"pomp",
                   "status":2
                },
                {
                   "device_id":2,
                   "function_desc":"less",
                   "function_title":"less",
                   "status":2
                }
             ],
             "image_path":"vfx",
             "status_id":2,
             "statuss":{
                "status_desc":"device is off",
                "status_title":"off"
             }
          }
       ]
    }
    

    This is my code:

    these are data models for defining json properties:

    class Base{
    //the type of our object is the array
      List<Device> _devices;
    
    
      Base(this._devices);
    
      List<Device> get devices => _devices;
    
      set devices(List<Device> value) {
        _devices = value;
      }
    }
    
    class Device {
      String _device_desc,_device_title,_image_path;
      int _status_id;
      List<function> _functions;
      List<Status> _statuss ;
    
      Device(this._device_desc, this._device_title, this._image_path,
          this._status_id, this._functions, this._statuss);
    
      List<Status> get statuss => _statuss;
    
      set statuss(List<Status> value) {
        _statuss = value;
      }
    
      List<function> get functions => _functions;
    
      set functions(List<function> value) {
        _functions = value;
      }
    
      int get status_id => _status_id;
    
      set status_id(int value) {
        _status_id = value;
      }
    
      get image_path => _image_path;
    
      set image_path(value) {
        _image_path = value;
      }
    
      get device_title => _device_title;
    
      set device_title(value) {
        _device_title = value;
      }
    
      String get device_desc => _device_desc;
    
      set device_desc(String value) {
        _device_desc = value;
      }
    }
    
    class Status {
      String _status_desc, _status_title;
    
      Status(this._status_desc, this._status_title);
    
      get status_title => _status_title;
    
      set status_title(value) {
        _status_title = value;
      }
    
      String get status_desc => _status_desc;
    
      set status_desc(String value) {
        _status_desc = value;
      }}
    class function {
       String _function_desc, _function_title;
       int _device_id, _status;
    
       function(this._function_desc, this._function_title, this._device_id,
           this._status);
    
       get status => _status;
    
       set status(value) {
         _status = value;
       }
    
       int get device_id => _device_id;
    
       set device_id(int value) {
         _device_id = value;
       }
    
       get function_title => _function_title;
    
       set function_title(value) {
         _function_title = value;
       }
    
       String get function_desc => _function_desc;
    
       set function_desc(String value) {
         _function_desc = value;
       }}
    

    and this is the stateful class :

    class MyHomePage extends StatefulWidget {
      var title;
    
      MyHomePage({Key key, this.title}) : super(key: key);
    
      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
    
    
      Future<Base> _getBase() async {
    var data = await http.get(Uri.encodeFull("http://192.168.1.111:5000/mobile-home"));
    var jsonData = json.decode(data.body);
    
    Base base = Base(jsonData);
      return Base(jsonData[0]);
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text(widget.title),
          ),
          body: Container(
            child: FutureBuilder(
              future: _getBase(),
              builder: (BuildContext context,  AsyncSnapshot snapshot) {
                if (snapshot.data == null) {
                  return Container(
                    child: Center(
                      child: Text("Loading..."),
                    ),
                  );
                } else {
                  return ListView.builder(
                    itemCount: snapshot.data.devices.length,
                    itemBuilder: (BuildContext context, int index) {
                      snapshot.data.devices.map<Widget>((devices){
                        return ListTile(
                          subtitle: Text(devices[index].device_desc.toString()),
                          title: Text(devices[index].device_title),
                          /*leading: CircleAvatar(
                          // ignore: argument_type_not_assignable
                          backgroundImage:  NetworkImage(snapshot.data[index].thumbnailUrl),
                        )*/
                        );
                      }
                      );
    
                    },
                  );
                }
              },
            ),
          ),
        );
      }
    }
    

    I got an error when while debugging:

     "type 'List<dynamic>' is not a subtype of type 'List<Device>'"
    

    I can not get the data from json.

  • ElhamKeshavarz
    ElhamKeshavarz over 5 years
    I added the error that it displays,"type 'List' is not a subtype of type 'List'"
  • ElhamKeshavarz
    ElhamKeshavarz over 5 years
    Actually, I am a beginner, and I want to write the code my self just for practice, but honestly saying that your answer was awesome, cause it is clarified and is just as simple as it can be!tnx for your great answer, and I`ll use this method for sure
  • ElhamKeshavarz
    ElhamKeshavarz over 5 years
    Thank you so much;) The article exactly mentioned my error, so I could solve my problem