AimanIrfan02
AimanIrfan02

Reputation: 51

My api always return null when i call the data

I am calling api below:

{
    "1": {
        "data": {
            "sensors": {
                "fuel": [
                    {
                        "sensor_value": 2.9081154,
                        "sensor_unit": "m",
                        "percentage": 83.09,
                        "value": 48705.07,
                        "unit": "L",
                        "status": "normal",
                        "sensor": "fuel",
                        "name": "main_fuel"
                    }
                ],
                "battery": [
                    {
                        "voltage": 4005,
                        "value": 100,
                        "status": "normal",
                        "unit": "%",
                        "sensor": "battery"
                    }
                ]
            },
            "latitude": null,
            "longitude": null,
            "speed": null,
            "ignition": null,
            "voltage": null,
            "gsm": null,
            "satellites": null,
            "tracked_at": "2020-11-23 03:35:47",
            "tracker": "jejaka",
            "temperature": null
        }
    },
    "2": {
        "data": {
            "sensors": {
                "fuel": [
                    {
                        "sensor_value": 2.90697352,
                        "sensor_unit": "m",
                        "percentage": 83.06,
                        "value": 48687.99,
                        "unit": "L",
                        "status": "normal",
                        "sensor": "fuel",
                        "name": "main_fuel"
                    }
                ],
                "battery": [
                    {
                        "voltage": 3901,
                        "value": 100,
                        "status": "normal",
                        "unit": "%",
                        "sensor": "battery"
                    }
                ]
            },
            "latitude": null,
            "longitude": null,
            "speed": null,
            "ignition": null,
            "voltage": null,
            "gsm": null,
            "satellites": null,
            "tracked_at": "2020-11-23 03:44:02",
            "tracker": "jejaka",
            "temperature": null
        }
    }
}

Here is my api call:

class Services{

  // ignore: missing_return
  static Future<Map<String, Tank>> fetchData() async {

    String url = 'http://192.168.10.17/api/device';
    Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
    final SharedPreferences prefs = await _prefs;
    final token = prefs.getString('access_token');
    final response = await http.get(url, headers: {
      'Authorization': 'Bearer $token'
    });

    print('Token: $token');

    if(response.statusCode == 200) {
     final tank = tankFromJson(response.body);
     return tank;
    }else if(response.statusCode == 400) {
      print('Connection to server is bad');
    }else if(response.statusCode == 500){
      print('No authorization');
    }
  }
}

This api need user token to return the api data as above. I have got the data but now when i implement the data, i get error below:

The getter 'data' was called on null.
Receiver: null
Tried calling: data

Here is how i implement the code. The api is in a listview. I have tried to put it in a future builder but i got error:

class TankCard extends StatefulWidget {
  @override
  _TankCardState createState() => _TankCardState();
}

class _TankCardState extends State<TankCard> {
  final _tankRepository = Services();
  Tank tank;

  initState() {
    Services.fetchData().then((tank){
      setState((){
        tank = tank;
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      padding: EdgeInsets.all(0),
      shrinkWrap: true,
      physics: NeverScrollableScrollPhysics(),
      itemCount: 2,
      itemBuilder: (BuildContext context, int index){
        return Column(
          children: [
            Container(
              margin: EdgeInsets.only(top: 10),
              width: MediaQuery.of(context).size.width * 1.1,
              child: Card(
                child: Column(
                  children: [
                    Container(
                      padding: EdgeInsets.only(top: 12),
                      child: Center(
                        child: Text('Tank 1 - Bukit Tinggi',
                        style: TextStyle(
                          fontSize: 14,
                          fontWeight: FontWeight.w600
                          )),
                        )
                      ),

                    Container(
                      padding: EdgeInsets.all(10),
                      child: SvgPicture.asset(
                        'assets/tank-icon-fill.svg',
                        // width: 50,
                      )
                    ),

                    Container(
                      margin: EdgeInsets.fromLTRB(0, 5, 5, 0),
                      child: Column(
                        children: [
                          Wrap(
                            children: [
                              Icon(Icons.bolt),
                              Container(
                                margin: EdgeInsets.only(top: 4),
                                child: Text('${tank.data.sensors.battery[0].value.toString()}%')
                              )
                            ],
                          ),
                          Container(
                            margin: EdgeInsets.only(left: 15),
                            child: Text('Battery', style: TextStyle(
                              fontSize: 10,
                              fontWeight: FontWeight.w300,
                            ),),
                          )
                        ],
                      ),
                    ),

The tank model i got from this url -> https://app.quicktype.io/
Any help would be appreciate.

Upvotes: 0

Views: 4134

Answers (2)

miguelik
miguelik

Reputation: 525

How to debug this type of problems w/ JSON in flutter:

  1. Check that your connection to the API is correct, before parsing the object, via logging the response.
  2. Check that you parsed object is correct (AKA, not null). Via logging the object.toString(). print(tank.toString()) in your case before returning the value
  3. Check in your Main that the value returned is not null
  4. Check/understand your JSON, go step by step trying to get 1 level deeper at a time (first print the full object, then print tank.1)

If you follow this steps you will find where it is not working

Upvotes: 0

chunhunghan
chunhunghan

Reputation: 54367

You can copy paste run full code below
Step 1: Use bool isLoading to check data is ready or not
Step 2: Use Map<String, Tank> payload
Step 3: In ListView use int no = index + 1; because Map data is "1" and "2"
Step 4: Use ${payload[no.toString().trim()].data.sensors.battery[0].value.toString()}

code snippet

  Map<String, Tank> payload;
  bool isLoading = true;

  initState() {
    Services.fetchData().then((tank) {
      setState(() {
        payload = tank;
        print(payload.toString());
        print(payload["1"].data.sensors.battery[0].value.toString());
        isLoading = false;
      });
    });
...     
 return isLoading
        ? CircularProgressIndicator()
        : ListView.builder(
            padding: EdgeInsets.all(0),
            shrinkWrap: true,
            physics: NeverScrollableScrollPhysics(),
            itemCount: 2,
            itemBuilder: (BuildContext context, int index) {
              int no = index + 1;
...
child: Text(
                        '${payload[no.toString().trim()].data.sensors.battery[0].value.toString()}%'))
              ],              

working demo

enter image description here

full code

import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;

Map<String, Tank> tankFromJson(String str) => Map.from(json.decode(str))
    .map((k, v) => MapEntry<String, Tank>(k, Tank.fromJson(v)));

String tankToJson(Map<String, Tank> data) => json.encode(
    Map.from(data).map((k, v) => MapEntry<String, dynamic>(k, v.toJson())));

class Tank {
  Tank({
    this.data,
  });

  Data data;

  factory Tank.fromJson(Map<String, dynamic> json) => Tank(
        data: Data.fromJson(json["data"]),
      );

  Map<String, dynamic> toJson() => {
        "data": data.toJson(),
      };
}

class Data {
  Data({
    this.sensors,
    this.latitude,
    this.longitude,
    this.speed,
    this.ignition,
    this.voltage,
    this.gsm,
    this.satellites,
    this.trackedAt,
    this.tracker,
    this.temperature,
  });

  Sensors sensors;
  dynamic latitude;
  dynamic longitude;
  dynamic speed;
  dynamic ignition;
  dynamic voltage;
  dynamic gsm;
  dynamic satellites;
  DateTime trackedAt;
  String tracker;
  dynamic temperature;

  factory Data.fromJson(Map<String, dynamic> json) => Data(
        sensors: Sensors.fromJson(json["sensors"]),
        latitude: json["latitude"],
        longitude: json["longitude"],
        speed: json["speed"],
        ignition: json["ignition"],
        voltage: json["voltage"],
        gsm: json["gsm"],
        satellites: json["satellites"],
        trackedAt: DateTime.parse(json["tracked_at"]),
        tracker: json["tracker"],
        temperature: json["temperature"],
      );

  Map<String, dynamic> toJson() => {
        "sensors": sensors.toJson(),
        "latitude": latitude,
        "longitude": longitude,
        "speed": speed,
        "ignition": ignition,
        "voltage": voltage,
        "gsm": gsm,
        "satellites": satellites,
        "tracked_at": trackedAt.toIso8601String(),
        "tracker": tracker,
        "temperature": temperature,
      };
}

class Sensors {
  Sensors({
    this.fuel,
    this.battery,
  });

  List<Fuel> fuel;
  List<Battery> battery;

  factory Sensors.fromJson(Map<String, dynamic> json) => Sensors(
        fuel: List<Fuel>.from(json["fuel"].map((x) => Fuel.fromJson(x))),
        battery:
            List<Battery>.from(json["battery"].map((x) => Battery.fromJson(x))),
      );

  Map<String, dynamic> toJson() => {
        "fuel": List<dynamic>.from(fuel.map((x) => x.toJson())),
        "battery": List<dynamic>.from(battery.map((x) => x.toJson())),
      };
}

class Battery {
  Battery({
    this.voltage,
    this.value,
    this.status,
    this.unit,
    this.sensor,
  });

  int voltage;
  int value;
  String status;
  String unit;
  String sensor;

  factory Battery.fromJson(Map<String, dynamic> json) => Battery(
        voltage: json["voltage"],
        value: json["value"],
        status: json["status"],
        unit: json["unit"],
        sensor: json["sensor"],
      );

  Map<String, dynamic> toJson() => {
        "voltage": voltage,
        "value": value,
        "status": status,
        "unit": unit,
        "sensor": sensor,
      };
}

class Fuel {
  Fuel({
    this.sensorValue,
    this.sensorUnit,
    this.percentage,
    this.value,
    this.unit,
    this.status,
    this.sensor,
    this.name,
  });

  double sensorValue;
  String sensorUnit;
  double percentage;
  double value;
  String unit;
  String status;
  String sensor;
  String name;

  factory Fuel.fromJson(Map<String, dynamic> json) => Fuel(
        sensorValue: json["sensor_value"].toDouble(),
        sensorUnit: json["sensor_unit"],
        percentage: json["percentage"].toDouble(),
        value: json["value"].toDouble(),
        unit: json["unit"],
        status: json["status"],
        sensor: json["sensor"],
        name: json["name"],
      );

  Map<String, dynamic> toJson() => {
        "sensor_value": sensorValue,
        "sensor_unit": sensorUnit,
        "percentage": percentage,
        "value": value,
        "unit": unit,
        "status": status,
        "sensor": sensor,
        "name": name,
      };
}

class Services {
  // ignore: missing_return
  static Future<Map<String, Tank>> fetchData() async {
    /*String url = 'http://192.168.10.17/api/device';
    Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
    final SharedPreferences prefs = await _prefs;
    final token = prefs.getString('access_token');
    final response = await http.get(url, headers: {
      'Authorization': 'Bearer $token'
    });

    print('Token: $token');
    */
    String jsonString = '''
    {
    "1": {
        "data": {
            "sensors": {
                "fuel": [
                    {
                        "sensor_value": 2.9081154,
                        "sensor_unit": "m",
                        "percentage": 83.09,
                        "value": 48705.07,
                        "unit": "L",
                        "status": "normal",
                        "sensor": "fuel",
                        "name": "main_fuel"
                    }
                ],
                "battery": [
                    {
                        "voltage": 4005,
                        "value": 100,
                        "status": "normal",
                        "unit": "%",
                        "sensor": "battery"
                    }
                ]
            },
            "latitude": null,
            "longitude": null,
            "speed": null,
            "ignition": null,
            "voltage": null,
            "gsm": null,
            "satellites": null,
            "tracked_at": "2020-11-23 03:35:47",
            "tracker": "jejaka",
            "temperature": null
        }
    },
    "2": {
        "data": {
            "sensors": {
                "fuel": [
                    {
                        "sensor_value": 2.90697352,
                        "sensor_unit": "m",
                        "percentage": 83.06,
                        "value": 48687.99,
                        "unit": "L",
                        "status": "normal",
                        "sensor": "fuel",
                        "name": "main_fuel"
                    }
                ],
                "battery": [
                    {
                        "voltage": 3901,
                        "value": 100,
                        "status": "normal",
                        "unit": "%",
                        "sensor": "battery"
                    }
                ]
            },
            "latitude": null,
            "longitude": null,
            "speed": null,
            "ignition": null,
            "voltage": null,
            "gsm": null,
            "satellites": null,
            "tracked_at": "2020-11-23 03:44:02",
            "tracker": "jejaka",
            "temperature": null
        }
    }
}
    ''';
    http.Response response = http.Response(jsonString, 200);
    if (response.statusCode == 200) {
      final tank = tankFromJson(response.body);
      return tank;
    } else if (response.statusCode == 400) {
      print('Connection to server is bad');
    } else if (response.statusCode == 500) {
      print('No authorization');
    }
  }
}

class TankCard extends StatefulWidget {
  @override
  _TankCardState createState() => _TankCardState();
}

class _TankCardState extends State<TankCard> {
  final _tankRepository = Services();
  Map<String, Tank> payload;
  bool isLoading = true;

  initState() {
    Services.fetchData().then((tank) {
      setState(() {
        payload = tank;
        print(payload.toString());
        print(payload["1"].data.sensors.battery[0].value.toString());
        isLoading = false;
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return isLoading
        ? CircularProgressIndicator()
        : ListView.builder(
            padding: EdgeInsets.all(0),
            shrinkWrap: true,
            physics: NeverScrollableScrollPhysics(),
            itemCount: 2,
            itemBuilder: (BuildContext context, int index) {
              int no = index + 1;
              return Column(children: [
                Container(
                    margin: EdgeInsets.only(top: 10),
                    width: MediaQuery.of(context).size.width * 1.1,
                    child: Card(
                        child: Column(children: [
                      Container(
                          padding: EdgeInsets.only(top: 12),
                          child: Center(
                            child: Text('Tank ${no} - Bukit Tinggi',
                                style: TextStyle(
                                    fontSize: 14, fontWeight: FontWeight.w600)),
                          )),
                      /*Container(
                          padding: EdgeInsets.all(10),
                          child: SvgPicture.asset(
                            'assets/tank-icon-fill.svg',
                            // width: 50,
                          )),*/
                      Container(
                        margin: EdgeInsets.fromLTRB(0, 5, 5, 0),
                        child: Column(
                          children: [
                            Wrap(
                              children: [
                                Icon(Icons.bolt),
                                Container(
                                    margin: EdgeInsets.only(top: 4),
                                    child: Text(
                                        '${payload[no.toString().trim()].data.sensors.battery[0].value.toString()}%'))
                              ],
                            ),
                            Container(
                              margin: EdgeInsets.only(left: 15),
                              child: Text(
                                'Battery',
                                style: TextStyle(
                                  fontSize: 10,
                                  fontWeight: FontWeight.w300,
                                ),
                              ),
                            )
                          ],
                        ),
                      ),
                    ]))),
              ]);
            });
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: TankCard(),
    );
  }
}

Upvotes: 2

Related Questions