【问题标题】:My api always return null when i call the data当我调用数据时,我的 api 总是返回 null
【发布时间】:2021-03-19 13:42:00
【问题描述】:

我在下面调用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 在列表视图中。我曾尝试将其放入未来的构建器中,但出现错误:

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

我从这个网址得到的坦克模型 -> https://app.quicktype.io/
任何帮助将不胜感激。

【问题讨论】:

    标签: api flutter flutter-layout flutter-dependencies


    【解决方案1】:

    您可以在下面复制粘贴运行完整代码
    第一步:使用boolisLoading检查数据是否准备好
    第 2 步:使用Map&lt;String, Tank&gt; payload
    第 3 步:在ListView 中使用int no = index + 1;,因为Map 数据是"1""2"
    第四步:使用${payload[no.toString().trim()].data.sensors.battery[0].value.toString()}

    代码sn-p

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

    【讨论】:

    • 谢谢你,它有效。我能知道为什么要使用有效载荷吗?
    • tank 与数据类型 Tank 混淆。所以我使用有效载荷来表示 Map
    【解决方案2】:

    如何在 Flutter 中使用 JSON 调试此类问题:

    1. 在解析对象之前,通过记录响应来检查您与 API 的连接是否正确。
    2. 检查您解析的对象是否正确(AKA,不为空)。通过记录 object.toString()。 print(tank.toString()) 在您的情况下返回值之前
    3. 在 Main 中检查返回的值不为 null
    4. 检查/理解您的 JSON,逐步尝试一次更深 1 级(首先打印完整对象,然后打印 tank.1)

    如果您按照这些步骤操作,您会发现它不工作的地方

    【讨论】:

    • 我应该把“1”放在哪里?
    • 我试过放 '1' 但它给了我错误
    • ${tank.1.data.sensors.battery[0].value}%' 检查 tank 是否为空 tank.toString()
    • 我已经尝试过 '${tank.1.data.sensors.battery[0].value.toString()}%' 但它给了我错误。它无法检测到 1
    • delete toString 最后,它不是那样使用的,它是在你的 json 检查槽中搜索一个值 tostring 不为空(对象本身)
    猜你喜欢
    • 1970-01-01
    • 2022-12-05
    • 1970-01-01
    • 2015-05-19
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多