Flutter:必须为 Text 小部件提供非空字符串。失败的断言:第 378 行 pos 10:'data != null'

时间:2021-06-22 10:11:25

标签: api flutter datatable

我从 API 获取数据并将其添加到数据表中,它工作正常,当我从下拉列表中选择月份时,我的数据表会根据从下拉列表中选择的月份进行修改,但最初它会打印此错误。

enter image description here

当我从下拉菜单中选择月份时它的变化

enter image description here

这里是代码



class MyAttendance extends StatefulWidget {
  

  @override
  _MyAttendanceState createState() => _MyAttendanceState();
}

class _MyAttendanceState extends State<MyAttendance> {
  //List<History> _historyList;
  List<History> historyList=[];
  String _selectedLeave;
  int monthIndex;
  int month;
  var monthsList=<String>[
      'January',
      'Febuary',
      'March',
      'April',
      'May',
      'June',
      'July',
      'Augest',
      'September',
      'October',
      'November',
      'December'
  ];
  String getdate="";
    void _getDate() {
    final String formattedDateTime =
        DateFormat('MM').format(DateTime.now()).toString();
    setState(() {
      getdate = formattedDateTime;
     print("date  "+getdate);
    });
  }
  _userDetails() async{
    SharedPreferences myPrefs=await SharedPreferences.getInstance();
    setState(() {
          getname=myPrefs.getString('name');         
        }); 
   }
   void initState() {
      _userDetails();
      _getDate();
      _getRecord();
    }
  Future<List<History>> _getRecord() async{
   Dio dio=new Dio();
   var data={
     'username':getname,
     'month':month
   };
   return dio
    .post(localhostUrlAttendanceHistory,data: json.encode(data))
      .then((onResponse) async {
        var jsonData=onResponse.data['data'];
        //List<History> historyList = [];
        for (var h in jsonData) {
          History history = History(
            h["Date"], 
            h["TimeIn"], 
            h["TimeOut"],
          );
          historyList.add(history);
        }
        return historyList;
      })
      .catchError((onerror){
        print(onerror.toString());
       
    });
  }
  Widget attendanceHistory(List<History> 

    historyList)=>  
        DataTable(columns: <DataColumn>[
        DataColumn(label: Text("Date"),),
        DataColumn(label: Text("Time in" ),),
        DataColumn(label: Text("Time out")
    )],
    rows: 
    historyList
      ?.map((element)=>DataRow(
      cells: <DataCell>[
      DataCell(Text(element?.date)),
      DataCell(Text(element?.timeIn)),
      DataCell(Text(element?.timeOut)),
    ]) )?.toList());
  
  
  TextEditingController fromDate=new TextEditingController();
  TextEditingController toDate=new TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new MyAppBar(title: Text("My Attendance"),onpressed: (){
       Navigator.push(context, MaterialPageRoute(builder: (context)=>Profile()));
   }),
    
    drawer:Emp_DrawerCode(),
   
    body:Stack(children: <Widget>[
       Container(
        padding: EdgeInsets.fromLTRB(25, 15, 0, 0),
        child: Text("Attendance history",style: TextStyle(fontSize: 30,color: Colors.blue[900],fontWeight: FontWeight.bold),),
        ),
        Container(
        padding: EdgeInsets.fromLTRB(45, 80, 10, 0),
        child:
        DropdownButton<String>(
        value: _selectedLeave==null?null:monthsList[monthIndex],    
        items: 
          monthsList   
          .map<DropdownMenuItem<String>>((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(value)
            );
          }).toList(),
          hint:Text(
            "Please choose a month",
          ),
          onChanged: (String value) {
            setState(() {
              _selectedLeave=value;
              monthIndex = monthsList.indexOf(value);
              month=monthIndex+1;
              print(month);
              print(_selectedLeave);
            });
          },
        ),
      ),

    Container(
    padding: EdgeInsets.fromLTRB(15, 150, 0, 0),
    child:SingleChildScrollView(
      scrollDirection: Axis.vertical,
    
    child: FutureBuilder(
    future: _getRecord(),
    
    builder: (BuildContext context, AsyncSnapshot<List<History>> snapshot) {
      // Check if the data has been received.
      if (snapshot.hasData) {
        // Return the widget and provide the received data.
        return attendanceHistory(snapshot.data);
      }
      return Center(child: CircularProgressIndicator(),);
      // print("data");
      // print(snapshot.data);
      // Text("No data is shown");
      //return attendanceHistory(snapshot.data);
     
    }
  ),
),)

   

    ]));
  }
}

class History {
  
  final String date;
  final String timeIn;
  final String timeOut;
  

  History(this.date, this.timeIn, this.timeOut);

}

错误

════════ Exception caught by widgets library ═══════════════════════════════════
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 378 pos 10: 'data != null'

The relevant error-causing widget was
FutureBuilder<List<History>>
lib\My_Attendance\MyAttendance.dart:171

更新: 几秒钟的红屏错误后,它显示了这个,我也没有从下拉列表中选择月份。

enter image description here

它现在发送这个错误

════════ Exception caught by widgets library ═══════════════════════════════════
The method 'map' was called on null.
Receiver: null
Tried calling: map<DataRow>(Closure: (History) => DataRow)
The relevant error-causing widget was
FutureBuilder<List<History>>

更新

错误enter image description here

更新:

  builder: (BuildContext context, AsyncSnapshot<List<History>> snapshot) {
      // Check if the data has been received.
      if(snapshot.connectionState==ConnectionState.done){
        if (snapshot.hasData) {
          return Center(
            child: Text('${snapshot.error} occured',
        style: TextStyle(fontSize: 18)),
          );
        }
        else if(snapshot.hasData){
         
            return attendanceHistory(snapshot.data);
          }
        
        // Return the widget and provide the received data.
          //return Center(child: CircularProgressIndicator(),);
      }
      //return attendanceHistory(snapshot.data);
      return Center(child: CircularProgressIndicator(),);
      // print("data");
      // print(snapshot.data);
      // Text("No data is shown");
      
     
    }
  ),

请帮助我如何解决它?

2 个答案:

答案 0 :(得分:1)

更好的做法是在从 API 获取数据时使用加载器。由于未来的构建器有一个属性来检查是否有来自 API 的响应。要检查这个只需使用

`FutureBuilder(
future: _getRecord(),

builder: (BuildContext context, 

AsyncSnapshot<List<History>> snapshot) {
  // Below line will check whether future has data or not
if (snapshot.connectionState == ConnectionState.done) {
  // If we got an error
  if (snapshot.hasError) {
    return Center(
      child: Text(
        '${snapshot.error} occured',
        style: TextStyle(fontSize: 18),
      ),
    );
      
    // if we got our data
  } else if (snapshot.hasData) {**strong text**
  if (snapshot.hasData) {
    
    return attendanceHistory(snapshot.data);
  }
 return Center(child: CircularProgressIndicator(),);
}`

否则您可以使用空感知运算符来处理空值,如下所示。

 Widget attendanceHistory(List<History> 

 historyList)=>  
 DataTable(columns: <DataColumn>[
DataColumn(label: Text("Date"),),
DataColumn(label: Text("Time in" ),),
DataColumn(label: Text("Time out")
)],
rows: 
historyList
?.map((element)=>DataRow(
cells: <DataCell>[
DataCell(Text(element?.date)),
DataCell(Text(element?.timeIn)),
DataCell(Text(element?.timeOut)),

]) )?.toList());

答案 1 :(得分:0)

当您将 null 值传递给 Text 小部件时会生成此错误。因此,为了避免这种情况,您可以在显示文本之前放置一个空检查条件,或者您可以将默认值传递给 Text 小部件。

 Widget attendanceHistory(List<History> historyList)=>  
  DataTable(columns: <DataColumn>[
    DataColumn(label: Text("Date"),),
    DataColumn(label: Text("Time in" ),),
    DataColumn(label: Text("Time out")
    )],
  rows: 
  historyList
  .map((element)=>DataRow(
    cells: <DataCell>[
    DataCell(Text(element.date ?? "N/A")),
    DataCell(Text(element.timeIn ?? "N/A")),
    DataCell(Text(element.timeOut ?? "N/A")),
  ])
  ).toList());

在获取记录时显示 CircularProgressIndicator。

Container(
    padding: EdgeInsets.fromLTRB(15, 150, 0, 0),
    child:SingleChildScrollView(
      scrollDirection: Axis.vertical,
    
    child: FutureBuilder(   //This is line 171
    future: _getRecord(),
    
    builder: (BuildContext context, AsyncSnapshot<List<History>> snapshot) {
      // Check if the data has been received.
      if (snapshot.hasData) {
        // Return the widget and provide the received data.
        return attendanceHistory(snapshot.data);
      }
     return Center(child: CircularProgressIndicator(),);
    }
  ),