如何解决在空值上使用空值检查运算符的问题。Rest API

huangapple go评论62阅读模式
英文:

How to solve Null check operator used on a null value. Rest API

问题

我的问题是dataFromAPI是null,但实际上不应该是null的。我尝试检查变量和其他一些内容,但我看不到哪里有null变量。我不知道是不是这个问题,还是其他什么问题,因为我看到这个错误比我的上一个错误更全局。

模型

// 要解析此JSON数据,请执行以下操作
//
//     final albaranesDeVentaDetalle = albaranesDeVentaDetalleFromJson(jsonString);

import 'dart:convert';

AlbaranesDeVentaDetalle albaranesDeVentaDetalleFromJson(String str) =>
    AlbaranesDeVentaDetalle.fromJson(json.decode(str));

String albaranesDeVentaDetalleToJson(AlbaranesDeVentaDetalle data) =>
    json.encode(data.toJson());

class AlbaranesDeVentaDetalle {
  VtaFacG vtaFacG;

  AlbaranesDeVentaDetalle({
    required this.vtaFacG,
  });

  factory AlbaranesDeVentaDetalle.fromJson(Map<String, dynamic> json) =>
      AlbaranesDeVentaDetalle(
        vtaFacG: VtaFacG.fromJson(json["vta_fac_g"]),
      );

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

class VtaFacG {
  DateTime fch;
  String numFac;
  int clt;
  double totFac;

  VtaFacG({
    required this.fch,
    required this.numFac,
    required this.clt,
    required this.totFac,
  });

  factory VtaFacG.fromJson(Map<String, dynamic> json) => VtaFacG(
        fch: DateTime.parse(json["fch"]),
        numFac: json["num_fac"],
        clt: json["clt"],
        totFac: json["tot_fac"]?.toDouble(),
      );

  Map<String, dynamic> toJson() => {
        "fch": fch.toIso8601String(),
        "num_fac": numFac,
        "clt": clt,
        "tot_fac": totFac,
      };
}

显示错误的代码部分

import 'dart:convert';
import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:velneoapp/api/modelos/api_model_detalles_de_albaranes.dart';

class DetalleDeAlbaranView extends StatefulWidget {
  const DetalleDeAlbaranView({super.key, required this.index});
  final int index;
  @override
  State<DetalleDeAlbaranView> createState() => _DetalleDeAlbaranViewState();
}

class _DetalleDeAlbaranViewState extends State<DetalleDeAlbaranView> {
  @override
  void initState() {
    super.initState();
    _getData();
  }

  bool _isLoaded = true;

  AlbaranesDeVentaDetalle? dataFromAPI;
  _getData() async {
    try {
      String url =
          "https://demoapi.velneo.com/verp-api/vERP_2_dat_dat/v1/vta_fac_g/3?api_key=api123";
      http.Response res = await http.get(Uri.parse(url));
      log("${res.body}");
      if (res.statusCode == 200) {
        log("hecho");
        dataFromAPI = AlbaranesDeVentaDetalle.fromJson(json.decode(res.body));
        _isLoaded = false;
        setState(() {});
      } else {
        throw ("Error during connection");
      }
    } catch (e) {
      log("Error");
      log(e.toString());
    }
  }

  @override
  void dispose() {
    super.dispose();
    _getData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Detalle de albaranes"),
      ),
      body: Padding(
        padding: EdgeInsets.all(8.0),
        child: Column(
          children: [
            Row(
              children: [
                const Text("TOTFAC: "),
                Text(dataFromAPI!.vtaFacG.totFac.toString()), // 增加了.toString()
              ],
            ),
            Row(
              children: [
                const Text("FCH: "),
                Text("${dataFromAPI!.vtaFacG.fch}"),
              ],
            ),
            Row(
              children: [
                const Text("NUM_FAC: "),
                Text(dataFromAPI!.vtaFacG.numFac),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

错误消息是:

════════ Exception caught by widgets library ═══════════════════════════════════
The following _TypeError was thrown building DetalleDeAlbaranView(dirty, state: _DetalleDeAlbaranViewState#d23f9):
Null check operator used on a null value
The relevant error-causing widget was
DetalleDeAlbaranView
main.dart:28
When the exception was thrown, this was the stack
...

我不确定空值在哪里,因为它说我创建的值是null。这是我第一次做不是列表的REST API,所以我不知道是否哪里出错了。

英文:

My problem is that dataFromAPI is null, when it isn't supposed to be. I tried to check the variables and some more, and i can't see where is the null variable. I don't know if it's that or something else, because i've seen this error is more global than my last one.

Model

// To parse this JSON data, do
//
//     final albaranesDeVentaDetalle = albaranesDeVentaDetalleFromJson(jsonString);
import &#39;dart:convert&#39;;
AlbaranesDeVentaDetalle albaranesDeVentaDetalleFromJson(String str) =&gt;
AlbaranesDeVentaDetalle.fromJson(json.decode(str));
String albaranesDeVentaDetalleToJson(AlbaranesDeVentaDetalle data) =&gt;
json.encode(data.toJson());
class AlbaranesDeVentaDetalle {
VtaFacG vtaFacG;
AlbaranesDeVentaDetalle({
required this.vtaFacG,
});
factory AlbaranesDeVentaDetalle.fromJson(Map&lt;String, dynamic&gt; json) =&gt;
AlbaranesDeVentaDetalle(
vtaFacG: VtaFacG.fromJson(json[&quot;vta_fac_g&quot;]),
);
Map&lt;String, dynamic&gt; toJson() =&gt; {
&quot;vta_fac_g&quot;: vtaFacG.toJson(),
};
}
class VtaFacG {
DateTime fch;
String numFac;
int clt;
double totFac;
VtaFacG({
required this.fch,
required this.numFac,
required this.clt,
required this.totFac,
});
factory VtaFacG.fromJson(Map&lt;String, dynamic&gt; json) =&gt; VtaFacG(
fch: DateTime.parse(json[&quot;fch&quot;]),
numFac: json[&quot;num_fac&quot;],
clt: json[&quot;clt&quot;],
totFac: json[&quot;tot_fac&quot;]?.toDouble(),
);
Map&lt;String, dynamic&gt; toJson() =&gt; {
&quot;fch&quot;: fch.toIso8601String(),
&quot;num_fac&quot;: numFac,
&quot;clt&quot;: clt,
&quot;tot_fac&quot;: totFac,
};
}

The code that shows it

import &#39;dart:convert&#39;;
import &#39;dart:developer&#39;;
import &#39;package:http/http.dart&#39; as http;
import &#39;package:flutter/material.dart&#39;;
import &#39;package:velneoapp/api/modelos/api_model_detalles_de_albaranes.dart&#39;;
class DetalleDeAlbaranView extends StatefulWidget {
const DetalleDeAlbaranView({super.key, required this.index});
final int index;
@override
State&lt;DetalleDeAlbaranView&gt; createState() =&gt; _DetalleDeAlbaranViewState();
}
//
class _DetalleDeAlbaranViewState extends State&lt;DetalleDeAlbaranView&gt; {
@override
void initState() {
super.initState();
_getData();
}
bool _isLoaded = true;
AlbaranesDeVentaDetalle? dataFromAPI;
_getData() async {
try {
String url =
&quot;https://demoapi.velneo.com/verp-api/vERP_2_dat_dat/v1/vta_fac_g/3?api_key=api123&quot;;
http.Response res = await http.get(Uri.parse(url));
log(&quot;${res.body}&quot;);
if (res.statusCode == 200) {
log(&quot;hecho&quot;);
dataFromAPI = AlbaranesDeVentaDetalle.fromJson(json.decode(res.body));
_isLoaded = false;
setState(() {});
} else {
throw (&quot;Error during connection&quot;);
}
} catch (e) {
log(&quot;Error&quot;);
log(e.toString());
}
}
@override
void dispose() {
super.dispose();
_getData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(&quot;Detalle de albaranes&quot;),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Row(
children: [
const Text(&quot;TOTFAC: &quot;),
Text(dataFromAPI!.vtaFacG.totFac as String),
],
),
Row(
children: [
const Text(&quot;FCH: &quot;),
Text(&quot;${dataFromAPI!.vtaFacG.fch}&quot;),
],
),
Row(
children: [
const Text(&quot;NUM_FAC: &quot;),
Text(dataFromAPI!.vtaFacG.numFac),
],
),
],
),
),
);
}
}

The error message is:


════════ Exception caught by widgets library ═══════════════════════════════════
The following _TypeError was thrown building DetalleDeAlbaranView(dirty, state: _DetalleDeAlbaranViewState#d23f9):
Null check operator used on a null value
The relevant error-causing widget was
DetalleDeAlbaranView
main.dart:28
When the exception was thrown, this was the stack
#0      _DetalleDeAlbaranViewState.build
detalle_de_albaran.dart:63
#1      StatefulElement.build
framework.dart:5198
#2      ComponentElement.performRebuild
framework.dart:5086
#3      StatefulElement.performRebuild
framework.dart:5251
#4      Element.rebuild
framework.dart:4805
#5      ComponentElement._firstBuild
framework.dart:5068
#6      StatefulElement._firstBuild
framework.dart:5242
#7      ComponentElement.mount
framework.dart:5062
...     Normal element mounting (220 frames)
#227    Element.inflateWidget
framework.dart:3971
#228    MultiChildRenderObjectElement.inflateWidget
framework.dart:6570
#229    Element.updateChild
framework.dart:3708
#230    RenderObjectElement.updateChildren
framework.dart:6153
#231    MultiChildRenderObjectElement.update
framework.dart:6595
#232    Element.updateChild
framework.dart:3686
#233    ComponentElement.performRebuild
framework.dart:5111
#234    StatefulElement.performRebuild
framework.dart:5251
#235    Element.rebuild
framework.dart:4805
#236    StatefulElement.update
framework.dart:5274
#237    Element.updateChild
framework.dart:3686
#238    ComponentElement.performRebuild
framework.dart:5111
#239    Element.rebuild
framework.dart:4805
#240    ProxyElement.update
framework.dart:5417
#241    Element.updateChild
framework.dart:3686
#242    ComponentElement.performRebuild
framework.dart:5111
#243    Element.rebuild
framework.dart:4805
#244    ProxyElement.update
framework.dart:5417
#245    _InheritedNotifierElement.update
inherited_notifier.dart:107
#246    Element.updateChild
framework.dart:3686
#247    ComponentElement.performRebuild
framework.dart:5111
#248    StatefulElement.performRebuild
framework.dart:5251
#249    Element.rebuild
framework.dart:4805
#250    StatefulElement.update
framework.dart:5274
#251    Element.updateChild
framework.dart:3686
#252    ComponentElement.performRebuild
framework.dart:5111
#253    Element.rebuild
#254    ProxyElement.update
framework.dart:5417
#255    _InheritedNotifierElement.update
inherited_notifier.dart:107
#256    Element.updateChild
framework.dart:3686
#257    ComponentElement.performRebuild
framework.dart:5111
#258    StatefulElement.performRebuild
framework.dart:5251
#259    Element.rebuild
framework.dart:4805
#260    StatefulElement.update
framework.dart:5274
#261    Element.updateChild
framework.dart:3686
#262    ComponentElement.performRebuild
framework.dart:5111
#263    StatefulElement.performRebuild
framework.dart:5251
#264    Element.rebuild
framework.dart:4805
#265    StatefulElement.update
framework.dart:5274
#266    Element.updateChild
framework.dart:3686
#267    SingleChildRenderObjectElement.update
framework.dart:6442
#268    Element.updateChild
framework.dart:3686
#269    SingleChildRenderObjectElement.update
framework.dart:6442
#270    Element.updateChild
framework.dart:3686
#271    ComponentElement.performRebuild
framework.dart:5111
#272    Element.rebuild
framework.dart:4805
#273    ProxyElement.update
framework.dart:5417
#274    Element.updateChild
framework.dart:3686
#275    ComponentElement.performRebuild
framework.dart:5111
#276    StatefulElement.performRebuild
framework.dart:5251
#277    Element.rebuild
framework.dart:4805
#278    BuildOwner.buildScope
framework.dart:2780
#279    WidgetsBinding.drawFrame
binding.dart:903
#280    RendererBinding._handlePersistentFrameCallback
binding.dart:358
#281    SchedulerBinding._invokeFrameCallback
binding.dart:1284
#282    SchedulerBinding.handleDrawFrame
binding.dart:1214
#283    SchedulerBinding._handleDrawFrame
binding.dart:1072
#284    _invoke (dart:ui/hooks.dart:142:13)
#285    PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:359:5)
#286    _drawFrame (dart:ui/hooks.dart:112:31)
════════════════════════════════════════════════════════════════════════════════```
I don&#39;t exactly know where the null value is, because it says that the value I created IS null. This is the first REST API I do where it isn&#39;t a list, so idk if I messed up somewhere.
</details>
# 答案1
**得分**: 0
这是不好的实践:
```dart
factory VtaFacG.fromJson(Map<String, dynamic> json) => VtaFacG(
fch: DateTime.parse(json["fch"]),
numFac: json["num_fac"],
clt: json["clt"],
totFac: json["tot_fac"]?.toDouble(),
);

想象一下,你的映射中的值不存在。你会在类型为String的numFac中设置一个空值。你可以将其设置为String?类型,或者你可以检查值是否为空,在这种情况下设置默认值。

numFac: json["num_fac"] != null ? json["num_fac"] : "",

或者简写为:

numFac: json["num_fac"] ?? "",

检查每个不可为空的变量,不仅仅是numFac。

至于你的问题:

你调用了一个API。你发送了一个请求到API,等待响应,解析JSON等等。这都需要时间。

当你正在进行这个调用并等待结果时,你的build方法已经被调用了。在你的build方法中,你已经访问了这个变量,但它还没有被设置,因为整个过程是异步运行的,需要时间。

你有两个选择:

  1. 使用你已经实现的标志。我不知道为什么你的_isLoaded变量默认为true,你应该将它设置为false,并在API调用之后设置为true(否则,这会让其他开发人员感到困惑)。在你的build方法中,你检查数据是否已经加载,如果没有,你可以显示一个空的Container或其他小部件,如下所示:
return _isLoaded ? Scaffold(...) : Container();
  1. 或者第二个选择是使用FutureBuilder,它基本上做了相同的事情,但是是Flutter官方的小部件。以下是Flutter官方文档中的一个示例:

FutureBuilder

英文:

This is bad practice:

 factory VtaFacG.fromJson(Map&lt;String, dynamic&gt; json) =&gt; VtaFacG(
fch: DateTime.parse(json[&quot;fch&quot;]),
numFac: json[&quot;num_fac&quot;],
clt: json[&quot;clt&quot;],
totFac: json[&quot;tot_fac&quot;]?.toDouble(),
);

Imagine your values inside your map don't exist. You will set a null value inside numFac which is of type String. You either make it of type String? or you just check if the value is null and set a default value in this case.

numFac: json[&quot;num_fac&quot;] != null ?  json[&quot;num_fac&quot;] : &quot;&quot;,

or in shortform:

numFac: json[&quot;num_fac&quot;] ?? &quot;&quot;,

Check every variable which isn't nullable, not only numFac.

To your problem:

You make a call to an api. You send a request to the api, you wait for the response, parse the json, etc. This all takes time.

While you are making this call and waiting for the result, your build method is already being called. In your build method you are accessing the variable already, but it has not been set yet, because the whole thing runs asynchronously and takes time.

You have 2 options:

You use your flag which you already implemented. I don't know why your _isLoaded variable is default to true, you should set it to false and set it to true after the api call (Otherwise, this will confuse other developers.). Inside your build method you check if the data is already loaded and if not you show an empty Container or another widget like this:

return _isLoaded ? Scaffold(..) : Container();

Or option 2 is you use a FutureBuilder, which basically does the same but is an official Flutter widget. Here is an example from flutter:

https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

huangapple
  • 本文由 发表于 2023年7月3日 21:55:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76605434.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定