【问题标题】:The getter 'storeNumber' was called on null (Receiver: null)在 null 上调用了 getter 'storeNumber'(接收方:null)
【发布时间】:2018-12-22 01:54:45
【问题描述】:

我正在尝试将数据从一个屏幕传递到另一个屏幕,但我不断收到 null 异常。每当我在第一个屏幕上填写表格并进入下一个屏幕时,我都会得到一个`

NoSuchMethodError:getter 'storeNumber' 在 null 上被调用

`

我的变量类是 ==> 这个实体类有我使用以下类中的表单填充的变量:

class StoreData {
  String _storeNumber;
  String _repName;
  String _repCell;
  DateTime _transactionDate = new DateTime.now();

  StoreData(
      this._storeNumber, this._repName, this._repCell, this._transactionDate);

  String get storeNumber => _storeNumber;

  set storeNumber(String value) {
    _storeNumber = value;
  }

  String get repName => _repName;

  DateTime get transactionDate => _transactionDate;

  set transactionDate(DateTime value) {
    _transactionDate = value;
  }

  String get repCell => _repCell;

  set repCell(String value) {
    _repCell = value;
  }

  set repName(String value) {
    _repName = value;
  }
}

主类(在本例中是向第二个屏幕发送数据的第一个屏幕)包括以下代码: 这个类有一个表单,它接受 3 个输入并将它们发送到第二个屏幕。

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

import 'FeedBack.dart';
import 'StoreData.dart';

void main() {
  runApp(MaterialApp(
    title: 'Navigation Basics',
    home: FirstScreen(),
  ));
}

//get our entity class
StoreData storeDate;

// get variables from entity class
String storeNumber = storeDate.storeNumber;
String repName = storeDate.repName;
String repCell = storeDate.repCell;
DateTime transactionDate = storeDate.transactionDate;

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() => _FirstScreenState();
}

class _FirstScreenState extends State<FirstScreen> {
  GlobalKey<FormState> _key = GlobalKey();
  bool _validate = false;

  _sendData() {
    Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => FeedBack(
              storeData: new StoreData(
                  storeNumber, repName, repCell, transactionDate))),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Test App'),
        ),
        body: new SingleChildScrollView(
          child: new Container(
            margin: new EdgeInsets.all(15.0),
            child: new Form(
              key: _key,
              autovalidate: _validate,
              child: formUI(),
            ),
          ),
        ),
      ),
    );
  }

  Widget formUI() {
    return new Column(
      children: <Widget>[
        new TextFormField(
            decoration: new InputDecoration(hintText: 'Store Number'),
            keyboardType: TextInputType.number,
            validator: validateRepCell,
            onSaved: (String val) {
              storeNumber = val;
            }),
        new TextFormField(
            decoration: new InputDecoration(hintText: 'Rep Full Name'),
            validator: validateRepName,
            onSaved: (String val) {
              repName = val;
            }),
        new TextFormField(
            decoration: new InputDecoration(hintText: 'Rep Phone Number'),
            keyboardType: TextInputType.number,
            validator: validateRepCell,
            onSaved: (String val) {
              repCell = val;
            }),
        new SizedBox(height: 15.0),
        new RaisedButton(
          onPressed: _sendData,
          child: new Text('Proceed'),
        )
      ],
    );
  }

// Validate Fields

  String validateRepCell(String value) {
    // String patttern = r'(^[a-zA-Z ]*$)';
    RegExp regExp = new RegExp(r'^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$');
    if (value.length == 0) {
      return "Store Number  is Required";
    } else if (!regExp.hasMatch(value)) {
      return "Store Number must be only have numbers";
    }
    return null;
  }

  String validateRepName(String value) {
    String patttern = r'(^[a-zA-Z ]*$)';
    RegExp regExp = new RegExp(patttern);
    if (value.length == 0) {
      return "Rep Name is Required";
    } else if (!regExp.hasMatch(value)) {
      return "Name must be a-z and A-Z";
    }
    return null;
  }


}

第二个屏幕的代码在这里:

class FeedBack extends StatelessWidget {
  final StoreData storeData;

  FeedBack({Key key, @required this.storeData}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("FeedBack Screen"),
      ),
      body: new Container(
        child: new Column(
          children: <Widget>[
            new RaisedButton(
              onPressed: _sendToDatabase,
              child: new Text('Press Me'),
            ),
            new Text("${storeData.storeNumber}"),
          ],
        ),
      ),
    );
  }

  _sendToDatabase() {
    Firestore.instance.runTransaction((Transaction transaction) async {
      CollectionReference reference = Firestore.instance.collection('Stores');

      await reference.add({"test": "test", "testII": "test"});
    });
  }
}

我已经尝试解决这个问题一周了,但是鉴于我对 Dart 和 Flutter 框架的新体验,这很难!

任何帮助将不胜感激,

【问题讨论】:

  • 由于以下行而出现错误:“String storeNumber = storeDate.storeNumber;”。当您在 null storeDate 对象上调用 getter 时。您可以使用我在答案中显示的方法。

标签: dart flutter


【解决方案1】:

您可以使用以下方法。

从您的代码中删除以下行:

//get our entity class
StoreData storeDate;

最初,现在没有可用的 StoreData 实例。

现在,像下面这样声明新变量:

String storeNumber;
String repName;
String repCell;
DateTime transactionDate;

然后在onSaved 方法中将表单值分配给它们。 因此,当您提交表单时,这些值将用于创建新的 StoreData 并将其传递到第二页。

这是您的 main.dart 文件的代码:

    import 'package:flutter/material.dart';

import 'FeedBack.dart';
import 'StoreData.dart';

void main() {
  runApp(MaterialApp(
    title: 'Navigation Basics',
    home: FirstScreen(),
  ));
}


// get variables from entity class
String storeNumber;
String repName;
String repCell;
DateTime transactionDate = DateTime.now();

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() => _FirstScreenState();
}

class _FirstScreenState extends State<FirstScreen> {
  GlobalKey<FormState> _key = GlobalKey();
  bool _validate = false;

  _sendData() {

    _key.currentState.save();

    Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => FeedBack(
              storeData: StoreData(
                  storeNumber, repName, repCell, transactionDate))),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Test App'),
        ),
        body: new SingleChildScrollView(
          child: new Container(
            margin: new EdgeInsets.all(15.0),
            child: new Form(
              key: _key,
              autovalidate: _validate,
              child: formUI(),
            ),
          ),
        ),
      ),
    );
  }

  Widget formUI() {
    return new Column(
      children: <Widget>[
        new TextFormField(
            decoration: new InputDecoration(hintText: 'Store Number'),
            keyboardType: TextInputType.number,
            validator: validateRepCell,
            onSaved: (String val) {
              storeNumber = val;
            }),
        new TextFormField(
            decoration: new InputDecoration(hintText: 'Rep Full Name'),
            validator: validateRepName,
            onSaved: (String val) {
              repName = val;
            }),
        new TextFormField(
            decoration: new InputDecoration(hintText: 'Rep Phone Number'),
            keyboardType: TextInputType.number,
            validator: validateRepCell,
            onSaved: (String val) {
              repCell = val;
            }),
        new SizedBox(height: 15.0),
        new RaisedButton(
          onPressed: _sendData,
          child: new Text('Proceed'),
        )
      ],
    );
  }

// Validate Fields

  String validateRepCell(String value) {
    // String patttern = r'(^[a-zA-Z ]*$)';
    RegExp regExp = new RegExp(r'^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)$');
    if (value.length == 0) {
      return "Store Number  is Required";
    } else if (!regExp.hasMatch(value)) {
      return "Store Number must be only have numbers";
    }
    return null;
  }

  String validateRepName(String value) {
    String patttern = r'(^[a-zA-Z ]*$)';
    RegExp regExp = new RegExp(patttern);
    if (value.length == 0) {
      return "Rep Name is Required";
    } else if (!regExp.hasMatch(value)) {
      return "Name must be a-z and A-Z";
    }
    return null;
  }


}

【讨论】:

  • 还能引用实体类 StoreData 吗?或者你的意思是只使用主类中的字段变量
  • 使用字段变量创建一个新的 StoreData。然后将其传递到另一个页面。因为在您的 main.dart 中,您正在创建变量并从 null StoreData 对象为它们分配值(这会导致您的情况出现错误)。这是没有必要的。只需创建变量并使用它们来创建新的 StoreData 对象。
  • 你是在暗示我应该摆脱带有私有变量的 StoreData 类,只在主类中创建字段变量并从那里开始?
  • 没有。您必须保留 StoreData 类。只需删除“StoreData storeDate;”从你的 main.dart 文件。您需要 StoreData 类来创建新商店并传递它。
  • 我已经更新了答案。现在你会更清楚。
猜你喜欢
  • 2021-06-09
  • 1970-01-01
  • 2021-09-07
  • 2023-03-20
  • 1970-01-01
  • 2021-09-13
  • 2021-03-06
  • 2021-06-25
  • 1970-01-01
相关资源
最近更新 更多