【问题标题】:I have one issue from migrating my flutter app to null_safety我在将我的颤振应用程序迁移到 null_safety 时遇到了一个问题
【发布时间】:2021-09-15 20:08:16
【问题描述】:

我将我的应用程序迁移到 null-safety。我遇到了一些错误,除了最后一个之外,我都能修复。

此页面是日历页面,发生错误的部分是我在构建日历时。我正在使用 table_calendar 插件。

我添加了“?”在为 _getEventsFroDay() 定义函数类型之后。我不知道这是否是正确的做法。

  1. 参数类型“列表?无法将 Function(DateTime)' 分配给参数类型 'List Function(DateTime)?'。

这是函数:

List<dynamic>? _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<dynamic> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return kEvents.putIfAbsent(eventDateUTC, () => eventList);
      }
    }
  }

This is where the error is occuring:
Widget _buildTableCalendar() {
    return TableCalendar(
      eventLoader: _getEventsForDay, <<<< ERROR HERE

这是我删除“?”后的错误消息来自列表? _getEventsForDay(日期时间天){。

这是完整的 .dart 文件:

// Example holidays
final Map<DateTime, List> _holidays = {
  DateTime(2020, 1, 1): ['New Year\'s Day'],
  DateTime(2020, 1, 6): ['Epiphany'],
  DateTime(2020, 2, 14): ['Valentine\'s Day'],
  DateTime(2020, 4, 21): ['Easter Sunday'],
  DateTime(2020, 4, 22): ['Easter Monday'],
};

final kNow = DateTime.now();
final kFirstDay = DateTime(kNow.year, kNow.month - 3, kNow.day);
final kLastDay = DateTime(kNow.year, kNow.month + 3, kNow.day);

final eventsRef = FirebaseFirestore.instance.collection('agency').doc(globals.agencyId).collection('event');
final _db = FirebaseFirestore.instance;
final _firestoreService = FirestoreService();
bool showSpinner = false;
DateTime? _selectedDay;
DateTime _focusedDay = DateTime.now();
LinkedHashMap<DateTime, List<Event>> kEvents = LinkedHashMap<DateTime, List<Event>>();

class AppointmentCalendarScreen extends StatefulWidget {
  AppointmentCalendarScreen({Key? key, this.title}) : super(key: key);

  final String? title;

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

class _AppointmentCalendarScreenState extends State<AppointmentCalendarScreen> with TickerProviderStateMixin {
  late final ValueNotifier<List<Event>> _selectedEvents;
  Map<DateTime, List>? _selectedEventsMap;
  late StreamController<Map<DateTime, List>> _streamController;
  late var eventDoc;

  @override
  void initState() {
    super.initState();

    _streamController = StreamController();
    _selectedDay = _focusedDay;
    _selectedEvents = ValueNotifier(_getEventsForDay(_selectedDay!));
  }

  @override
  void dispose() {
    _selectedEvents.dispose();
    _streamController.close();

    super.dispose();
  }

  List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<Event> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return (kEvents.putIfAbsent(eventDateUTC, () => eventList))??[];

      }
    }
  }

  void _onDaySelected(DateTime selectedDay, DateTime focusedDay) {
    if (!isSameDay(_selectedDay, selectedDay)) {
      setState(() {
        _selectedDay = selectedDay;
        _focusedDay = focusedDay;
      });

      _selectedEvents.value = _getEventsForDay(selectedDay);
    }
  }

  void _onVisibleDaysChanged(DateTime first, DateTime last,
      CalendarFormat format) {
  }

  void _onCalendarCreated(DateTime first, DateTime last,
      CalendarFormat format) {
  }

  @override
  Widget build(BuildContext context) {
    final eventProvider = Provider.of<EventProvider>(context);
    FirebaseFirestore _db = FirebaseFirestore.instance;

    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Image.asset('assets/images/Appbar_logo.png',
                fit: BoxFit.cover, height: 56),
          ],
        ),
      ),
      backgroundColor: Colors.white,
      resizeToAvoidBottomInset: false,
      body: Column(
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          StreamBuilder(
            stream: _db.collection('agency').doc(globals.agencyId).collection('event')
              .where('eventDate', isGreaterThanOrEqualTo: kFirstDay)
              .where('eventDate', isLessThanOrEqualTo: kLastDay)
                    .snapshots().map((snapshot) => snapshot.docs
              .map((document) => Event.fromFirestore(document.data()))
              .toList()),
            builder: (context, AsyncSnapshot <List<Event>> eventsSnapShot) {
              if (eventsSnapShot.hasData) {

                return _buildTableCalendar();
              } else {
                return CircularProgressIndicator();
              }
            },
          ),
          const SizedBox(height: 8.0),
          //_buildButtons(),
          ElevatedButton(
            onPressed: () async {
              setState(() {
                showSpinner = true;
              });
              try {
                globals.newAgency = true;

                Navigator.of(context).pushReplacement(MaterialPageRoute(
                    builder: (context) => AddEventScreen()));

                setState(() {
                  showSpinner = false;
                });
              } catch (e) {
                // todo: add better error handling
                print(e);
              }
            },
            child: Text('Add Event'),
          ),
          const SizedBox(height: 8.0),
          Expanded(child: _buildEventList()),
        ],
      ),
    );
  }

  // Simple TableCalendar configuration (using Styles)
  Widget _buildTableCalendar() {
    return TableCalendar(
      firstDay: kFirstDay,
      lastDay: kLastDay,
      focusedDay: _focusedDay,
      selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
      locale: 'en_US',
      eventLoader: (day) {
        return _getEventsForDay(day);
      },
      startingDayOfWeek: StartingDayOfWeek.sunday,
      calendarStyle: CalendarStyle(
        isTodayHighlighted: true,
        selectedDecoration: BoxDecoration(color: Colors.deepOrange[400]),
        todayDecoration: BoxDecoration(color: Colors.deepOrange[200]),
        markerDecoration: BoxDecoration(color: Colors.deepPurpleAccent),
        outsideDaysVisible: false,
      ),
      headerStyle: HeaderStyle(
        formatButtonTextStyle:
        TextStyle().copyWith(color: Colors.white, fontSize: 15.0),
        formatButtonDecoration: BoxDecoration(
          color: Colors.deepOrange[400],
          borderRadius: BorderRadius.circular(16.0),
        ),
      ),
      onDaySelected: (selectedDay, focusedDay) {
        setState(() {
          _selectedDay = selectedDay;
          _focusedDay = focusedDay; // update `_focusedDay` here as well
        });
      },
      onPageChanged: (focusedDay) {
        _focusedDay = focusedDay;
      },
    );
  }

  Widget _buildHolidaysMarker() {
    return Icon(
      Icons.add_box,
      size: 20.0,
      color: Colors.blueGrey[800],
    );
  }

  Widget _buildEventList() {
    final _db = FirebaseFirestore.instance;

    return Container(
      child: StreamBuilder<QuerySnapshot>(
        //stream: FirestoreService().getEventStream(_focusedDay),
        stream: _db.collection('agency').doc(globals.agencyId).collection(
            'event').where('eventDate', isEqualTo: _focusedDay).snapshots(),
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return Center(
                child: const Text(
                  'Loading...',
                  style: TextStyle(
                      fontSize: 20, fontWeight: FontWeight.bold),
                ));
          } else {
            var doc = snapshot.data!.docs;
            return new ListView.builder(
                itemCount: doc.length,
                itemBuilder: (BuildContext context, int index) {
                  Event _event = Event.fromFirestore(
                      doc[index].data() as Map<String, dynamic>);
                  return ListTile(
                    isThreeLine: true,
                    title: Text(
                      '${_event.eventName ?? 'n/a'}',
                      style: TextStyle(
                          fontWeight: FontWeight.w900,
                          color: Colors.blueAccent),
                    ),
                    subtitle: Text.rich(TextSpan(
                        text:
                        '${DateFormat('EE MM-dd-yyyy').format(_event.eventDate!) ?? 'n/a'}\n'
                        '${DateFormat('h:mm a').format(_event.eventStartTime!) ?? 'n/a'}, '
                        'Duration: ${_event.eventDuration ?? 'n/a'} minutes',
                        children: <TextSpan>[
                          TextSpan(
                            text:
                            '\n${_event.eventDescription ?? 'n/a'}',
                            style: TextStyle(
                                fontWeight: FontWeight.w900,
                                color: Colors.blueGrey),
                          )
                        ])),
                    //trailing: Text('MLS#: ${_event.mlsNumber ?? 'n/a'}'),
                    onTap: () {
                      globals.newTrxn = false;
                      /*
                    Navigator.of(context).push(MaterialPageRoute(
                        builder: (context) =>
                            AddEventScreen(
                                doc[index].data())));

                     */
                    },
                  );
                }
            );
          }
        },

      ),
    );
  }

  Map<DateTime, List>? convertToMap(List<Event> item) {
    Map<DateTime, List>? result;

    for (int i = 0; i < item.length; i++) {
      Event data = item[i];
      //get the date and convert it to a DateTime variable
      //DateTime currentDate = DateFormat('MM-dd-yyyy - kk:mm').format(data.eventDate);
      DateTime currentDate = DateTime(data.eventDate!.year, data.eventDate!.month, data.eventDate!.day, data.eventDate!.hour, data.eventDate!.minute);

      List eventNames = [];
      //add the event name to the the eventNames list for the current date.
      //search for another event with the same date and populate the eventNames List.
      for (int j = 0; j < item.length; j++) {
        //create temp calendarItemData object.
        Event temp = item[j];
        //establish that the temp date is equal to the current date
        if (data.eventDate == temp.eventDate) {
          //add the event name to the event List.
          eventNames.add(temp.eventName);
        } //else continue
      }

      //add the date and the event to the map if the date is not contained in the map
      if (result == null) {
        result = {
          currentDate: eventNames
        };
      } else {
        result[currentDate] = eventNames;
      }
      return result;
    }
  }
}

【问题讨论】:

  • 你能告诉我eventLoader的类型吗?
  • @TipuSultan 这里是在 github 中找到的代码中的声明 (github.com/aleksanderwozniak/table_calendar/blob/master/lib/src/…): final List Function(DateTime day)?事件加载器;
  • 这是作者在示例中使用此代码的方式: List _getEventsForDay(DateTime day) { // 实现示例 return kEvents[day] ?? [];但如果我这样做,我会收到此错误:正文可能正常完成,导致返回“null”,但返回类型可能是不可为空的类型
  • 请查看我的更新答案

标签: flutter migration dart-null-safety


【解决方案1】:

如果您的列表是Event 类型,那么您应该从_getEventsForDay 函数返回List&lt;Event&gt;? 而不是List&lt;dynamic&gt;?。希望这能解决您的问题。

已编辑:

我的错。我已阅读文档,它说,您可以将 eventloader 的值设为 null 或返回类型应为非 null 列表的函数。

那么,在您的情况下,您要返回一个列表?这意味着函数返回类型可以为空。这就是你得到错误的原因。

List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<dynamic> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return kEvents.putIfAbsent(eventDateUTC, () => eventList);
      }
    }
  }

第二个问题:

现在这个错误告诉kEvents.putIfAbsent(eventDateUTC, () =&gt; eventList); 可能返回null。这是不可接受的,因为我们的函数现在不会返回任何 null 值。在这种情况下,我们可以像这样使用空检查运算符。

return (kEvents.putIfAbsent(eventDateUTC, () =&gt; eventList))??[];

希望这能解决您的问题。

【讨论】:

  • 感谢您的回复。当我删除“?”我收到此错误:正文可能正常完成,导致返回“null”,但返回类型可能是不可为空的类型。此错误出现在函数的声明中。我不知道如何在函数上解决这个问题。还有什么建议吗?
  • 我已经添加了错误消息的屏幕截图,我现在正在原始帖子中。正如您在原始代码 sn-p 中看到的,我有一个 return 语句。
  • 谢谢@TipuSultan,但是,我仍然遇到同样的错误。我已经编辑了原始帖子并在底部添加了完整的代码。
【解决方案2】:
  List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<dynamic> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return kEvents.putIfAbsent(eventDateUTC, () => eventList);
      }
    }
  }

由于您的 for 里面有一个 if 子句,并且 eventDoc.length 可以为空,因此您的函数永远不会到达 return 语句:

return kEvents.putIfAbsent(eventDateUTC, () => eventList);

所以IDE告诉你需要在函数末尾添加一个return,这样它就可以return null,如果eventDoc。 length 或 if 子句永远不会满足。

要解决您的问题,请添加:

return [];

在你的 for 循环之后,在函数的末尾:

List<Event> _getEventsForDay(DateTime day) {
    // kEvents is a linkedHashMap
    for (int i = 0; i < eventDoc.length; i++ ) {
      DateTime eventDate = eventDoc[i].eventDate;
      DateTime eventDateUTC = eventDate.toUtc();
      if (day.year == eventDate.year && day.day == eventDate.day && day.month == eventDate.month) {
        List<dynamic> eventList = [];
        eventList.add(eventDoc[i].agencyId);
        eventList.add(eventDoc[i].agentId);
        eventList.add(eventDoc[i].eventDate);
        eventList.add(eventDoc[i].eventDescription);
        eventList.add(eventDoc[i].eventDuration);
        eventList.add(eventDoc[i].eventName);
        eventList.add(eventDoc[i].eventStartTime);
        //print('kEvents: $kEvents');
        return kEvents.putIfAbsent(eventDateUTC, () => eventList);
      }
    }

    return [];
  }

【讨论】:

  • 我很抱歉这么愚蠢,但我添加了“return null;”但现在我在“null”上收到此错误:无法从方法“_getEventsForDay”返回“Null”类型的值,因为它的返回类型为“List”。我将 null 更改为 [] 并且错误消失了。这是正确的做法吗?
  • 哦,我明白了,它返回 null 失败,因为 List 不可为空,我的错!如果你返回 []。它将返回一个空列表,如果你设置 List?,那么你可以返回 null ,这实际上取决于你在哪里调用 _getEventsForDay 函数,如果你处理它为 null 或者一个空列表就足够了。跨度>
猜你喜欢
  • 2021-06-14
  • 2021-09-22
  • 2019-10-07
  • 2022-08-14
  • 1970-01-01
  • 2022-11-07
  • 1970-01-01
  • 2021-10-14
  • 2023-03-23
相关资源
最近更新 更多