Мой api всегда возвращает null при вызове данных

#api #flutter #flutter-layout #flutter-dependencies

#API #flutter #flutter-layout #flutter-зависимости

Вопрос:

Я вызываю api ниже:

 {
    "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
        }
    }
}
 

Вот мой вызов api:

 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');
    }
  }
}
 

Этому api требуется пользовательский токен для возврата данных api, как указано выше. Я получил данные, но теперь, когда я реализую данные, я получаю сообщение об ошибке ниже:

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

Вот как я реализую код. API находится в listview. Я попытался поместить его в будущий конструктор, но я получил ошибку:

 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,
                            ),),
                          )
                        ],
                      ),
                    ),
 

Модель резервуара, которую я получил по этому URL-адресу -> https://app.quicktype.io /
Буду признателен за любую помощь.

Ответ №1:

Вы можете скопировать вставить выполнить полный код ниже
Шаг 1: Использовать bool isLoading для проверки готовности данных или нет
Шаг 2: Использовать Map<String, Tank> payload
Шаг 3: ListView Используется int no = index 1; , поскольку Map данные "1" и "2"
Шаг 4: использование ${payload[no.toString().trim()].data.sensors.battery[0].value.toString()}

фрагмент кода

   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()}%'))
              ],              
 

рабочая демонстрация

введите описание изображения здесь

полный код

 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(),
    );
  }
}
 

Комментарии:

1. Спасибо, чувак, это работает. Могу ли я узнать, зачем использовать полезную нагрузку?

2. tank путают с типом данных Tank. поэтому я использую полезную нагрузку для представления Map<String, Tank>

Ответ №2:

Как отлаживать проблемы такого типа с помощью / JSON в flutter:

  1. Перед анализом объекта проверьте правильность вашего подключения к API посредством регистрации ответа.
  2. Убедитесь, что проанализированный вами объект указан правильно (иначе говоря, не null). Через регистрацию object.toString(). print(tank.toString()) в вашем случае перед возвратом значения
  3. Проверьте в своем основном, что возвращаемое значение не равно null
  4. Проверьте / поймите свой JSON, идите шаг за шагом, пытаясь получить 1 уровень глубже за раз (сначала распечатайте полный объект, затем распечатайте tank.1)

Если вы выполните следующие действия, вы обнаружите, где он не работает

Комментарии:

1. куда я должен поместить «1»?

2. я пробовал ставить ‘1’, но это выдает мне ошибку

3. ${tank.1.data.sensors.battery[0].value}%’ Проверьте, что резервуар не является нулевым резервуаром. toString()

4. я пробовал это ‘${tank.1.data.sensors.battery[0].value. toString()}%’ но это выдает ошибку. Он не может обнаружить значение 1

5. удалите toString в конце, он не используется таким образом, он ищет значение tostring в вашем json check tank не равно null (сам объект)