发布 http 请求:在 null 颤动上调用了 getter 'length'

Posted

技术标签:

【中文标题】发布 http 请求:在 null 颤动上调用了 getter \'length\'【英文标题】:post http request : The getter 'length' was called on null flutter发布 http 请求:在 null 颤动上调用了 getter 'length' 【发布时间】:2020-01-21 08:17:32 【问题描述】:

我想在调用 API 时创建一个用户。 我用 URL 创建了一个 Future 并在屏幕页面中调用我的模型。 我在表单中获取所有数据,但是当我调用我的 API 时,出现此错误:

在 null 上调用了 getter 'length'...

用户模型:

class Candidate 
  int id;
  String firstname;
  String lastname;
  String email;

  Candidate(this.id, this.firstname, this.lastname, this.email);

  factory Candidate.fromJson(Map<String, dynamic> json) 
    return Candidate(
      id: json['id'],
      firstname: json['firstname'],
      lastname: json['lastname'],
      email: json['email'],
    );
  

  Map toMap() 
    var map = new Map<String, dynamic>();
    map["id"] = id;
    map["firstname"] = firstname;
    map["lastname"] = lastname;
    map["email"] = email;
    return map;
  

  Future<Candidate> candidateAuth(Map body) async 
    String url = 'http://10.0.2.2:3000/v1/api/auth/candidate';
    final response = await http.post(url, body: body, headers: "Accept": "application/json");

    if (response.statusCode == 201) 
      return Candidate.fromJson(json.decode(response.body));
     else 
      throw Exception('Failed auth');
    
  

编辑:

我在修改后添加了登录页面的所有代码。

在登录页面:

import 'package:blackbox/models/candidate_model.dart';
import 'package:blackbox/screens/theme_page.dart' as t;
import 'package:flutter/material.dart';

class Login extends StatefulWidget 
  @override
  State<StatefulWidget> createState() 
    return new _Login();
  


class _Login extends State<Login> 
  final _formKey = GlobalKey<FormState>();
  String email, lastname, firstname;

  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      appBar: new AppBar(
        leading: Image.asset(
          'assets/img/logo_ineat.png',
          fit: BoxFit.contain,
          height: 32,
        ),
        title: Text('BlackBox'),
      ),
      body: new Center(
        child: new SingleChildScrollView(
          child: new Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              new Container(
                margin: EdgeInsets.only(top: 10.0, bottom: 20.0),
                alignment: Alignment.topCenter,
                child: new Text('Se Connecter',
                    style: new TextStyle(
                        fontSize: 24, fontWeight: FontWeight.bold)),
              ),
              new Card(
                elevation: 10,
                color: Colors.pink,
                child: new Container(
                  width: MediaQuery.of(context).size.width / 2,
                  height: MediaQuery.of(context).size.height / 3,
                  child: new Image.asset('assets/img/logo_ineat.png',
                      fit: BoxFit.contain),
                ),
              ),
              new Form(
                key: _formKey,
                child: new Column(
                  children: <Widget>[
                    new Row(
                      children: <Widget>[
                        new Container(
                          width: MediaQuery.of(context).size.width / 5,
                          margin:
                              EdgeInsets.only(left: 10, top: 5, right: 10.0),
                          child: new Text("Nom : "),
                        ),
                        new Container(
                          width: MediaQuery.of(context).size.width / 1.4,
                          margin: EdgeInsets.only(top: 5, right: 10.0),
                          child: new TextFormField(
                            keyboardType: TextInputType.text,
                            decoration: new InputDecoration(
                                labelText: 'Entrez votre nom'),
                            validator: (value) 
                              if (value.isEmpty) 
                                return 'Veuillez remplir le champ nom';
                              
                              lastname = value;
                              return null;
                            ,
                          ),
                        ),
                      ],
                    ),
                    new Row(
                      children: <Widget>[
                        new Container(
                          width: MediaQuery.of(context).size.width / 5,
                          margin:
                              EdgeInsets.only(left: 10, top: 5, right: 10.0),
                          child: new Text("Prénom : "),
                        ),
                        new Container(
                          width: MediaQuery.of(context).size.width / 1.4,
                          margin: EdgeInsets.only(top: 5, right: 10.0),
                          child: new TextFormField(
                            keyboardType: TextInputType.text,
                            decoration: new InputDecoration(
                                labelText: 'Entrez votre prénom'),
                            validator: (value) 
                              if (value.isEmpty) 
                                return 'Veuillez remplir le champ prénom';
                              
                              firstname = value;
                              return null;
                            ,
                          ),
                        ),
                      ],
                    ),
                    new Row(
                      children: <Widget>[
                        new Container(
                          width: MediaQuery.of(context).size.width / 5,
                          margin:
                              EdgeInsets.only(left: 10, top: 5, right: 10.0),
                          child: new Text("Email : "),
                        ),
                        new Container(
                          width: MediaQuery.of(context).size.width / 1.4,
                          margin: EdgeInsets.only(top: 5, right: 10.0),
                          child: new TextFormField(
                            keyboardType: TextInputType.emailAddress,
                            decoration: new InputDecoration(
                                labelText: 'Entrez votre email'),
                            validator: (value) 
                              if (value.isEmpty) 
                                return 'Veuillez remplir le champ email';
                              
                              email = value.toLowerCase();
                              return null;
                            ,
                          ),
                        ),
                      ],
                    ),
                    new Container(
                      margin: EdgeInsets.only(top: 30, bottom: 5, right: 10.0),
                      alignment: Alignment.bottomRight,
                      child: new RaisedButton.icon(
                          onPressed: () 
                            setState(() async 
                              if (_formKey.currentState.validate()) 
                                Candidate newPost = new Candidate(
                                  lastname: lastname,
                                  firstname: firstname,
                                  email: email,
                                );
                                var candidate = await Candidate()
                                    .candidateAuth(body: newPost.toMap());
                              
                            );
                          ,
                          icon: Icon(Icons.check),
                          label: Text('Valider')),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  


错误信息:

发生异常。 NoSuchMethodError (NoSuchMethodError: 在 null 上调用了 getter 'length'。 接收者:null 尝试调用: length) 在处理手势时抛出以下断言: setState() 回调参数返回一个 Future。 setState() 方法 on _Login#e2125 是使用返回 Future 的闭包或方法调用的。 也许它被标记为“异步”。而不是表演 调用 setState() 中的异步工作,首先执行工作 (不更新小部件状态),然后同步更新 调用 setState() 中的状态

【问题讨论】:

你能显示详细的错误信息吗? 发生异常。 NoSuchMethodError(NoSuchMethodError:在 null 上调用了 getter 'length'。接收方:null 尝试调用:length)在处理手势时引发了以下断言:setState() 回调参数返回了 Future。 _Login#e2125 上的 setState() 方法是使用返回 Future 的闭包或方法调用的。也许它被标记为“异步”。不要在 setState() 调用中执行异步工作,而是先执行工作(不更新小部件状态),然后在 setState() 调用中同步更新状态。 请问格式化文本 【参考方案1】:

原来是这样的:

headers: 'Content-type': 'application/json','Accept': 'application/json'

【讨论】:

【参考方案2】:

因为candidateAuth返回Future,所以需要加上await

Candidate newPost = new Candidate(
  lastname: lastname,
  firstname: firstname,
  email: email,
);
var candidate = await Candidate().candidateAuth(body: newPost.toMap());

更新:

根据错误信息从setState中删除async

onPressed: () async 
  if (_formKey.currentState.validate()) 
    Candidate newPost = new Candidate(
        lastname: lastname,
        firstname: firstname,
        email: email,);
    var candidate = await Candidate().candidateAuth(body: newPost.toMap());

    setState(() 
      // do what you need with candidate here
    );
     
,

【讨论】:

你好@Spatz,好的,我测试过了,但我一直有这个错误。 好的,我这样做了,但是我在 setState() 中设置了什么?我在我的不同容器中对候选人做我需要的事情。如果我这样做,我仍然有错误消息...... @Spatz map result : id: null, firstname: toto, lastname: toto, email: toto@toto.fr id null 因为基数自动递增所以为什么程序返回 null 错误...跨度>

以上是关于发布 http 请求:在 null 颤动上调用了 getter 'length'的主要内容,如果未能解决你的问题,请参考以下文章

如何解决在 null 上调用了方法“[]”。在颤动中[重复]

处理异常 HTTP 请求颤动

处理http请求时如何修复“在null上调用的方法'取消'”

空异常颤动时调用了方法“[]”

来自 API 请求的错误“在 null 上调用了方法 '[]'。接收方:null 尝试调用:[](0)”更新

如何在颤动的 Web http 请求中添加标头?