- 我在代码中遇到错误,
LateInitializationError: Field 'sorting' has not been initialized.
我需要确保build
在 init 中的每个函数完成后执行。initsorting
发生在initializeSorting()
函数中,但显然build
是在sorting
初始化之前执行的。 - 我也不知道为什么,但打印的打印内容不应该打印
tasks
空列表,同时打印内容还可以。我正在从另一个小部件传递数据,如下所示:。已经尝试过可空值的方法,但没有成功。完全不知道为什么 和都是空的。[]
user
taskTitle
TaskSortWidget(onSort: sortTasks, user: user, taskTitle: taskTitle, tasks: tasks)
widget.tasks
tasks
- 我将非常感谢任何帮助。
完整的小部件排序代码
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:taskease/classes/task.dart';
enum SortOrder {
Ascending,
Descending,
}
enum TaskSortingCriteria {
Priority,
DueDate,
FromDate,
}
class TaskSortWidget extends StatefulWidget {
final Function(List<Task>) onSort;
final String user;
final String taskTitle;
final List<Task> tasks;
TaskSortWidget(
{required this.onSort,
required this.user,
required this.taskTitle,
required this.tasks});
@override
_TaskSortWidgetState createState() => _TaskSortWidgetState();
}
class _TaskSortWidgetState extends State<TaskSortWidget> {
bool loading = false;
late List<Task> tasks;
late CollectionReference _collectionRef;
late final String taskTitle;
late final String user;
late Map<String, dynamic> sorting;
void initState() {
super.initState();
setState(() {
user = widget.user;
taskTitle = widget.taskTitle;
});
tasks = widget.tasks;
_collectionRef = FirebaseFirestore.instance
.collection('Users')
.doc(user)
.collection('Tasks');
initializeSorting();
}
Future<void> initializeSorting() async {
setState(() {
loading = true;
});
DocumentSnapshot querySnapshot = await _collectionRef.doc(taskTitle).get();
if (querySnapshot.exists) {
Map<String, dynamic> data = querySnapshot.data() as Map<String, dynamic>;
setState(() {
sorting = data['sorting'];
});
} else {
print(
'(sort widget, this message should never show!) Sorting does not exist. Creating one...'); //this else will never execute
await FirebaseFirestore.instance
.collection('Users')
.doc(user)
.collection('Tasks')
.doc(taskTitle)
.set({
'sorting': {
'_currentSortOrderPriority': {2, 'Ascending'},
'_currentSortOrderDueDate': {0, 'Ascending'},
'_currentSortOrderFromDate': {1, 'Ascending'},
}
}, SetOptions(merge: true));
}
setState(() {
loading = false;
});
sortTasks();
}
void sortTasks() {
for (int i = 0; i < sorting.length; i++) {
for (var entry in sorting.entries) {
if (entry.value[0] == i) {
SortOrder sortOrder = entry.value[1] == 'Ascending'
? SortOrder.Ascending
: SortOrder.Descending;
switch (entry.key) {
case '_currentSortOrderPriority':
tasks.sort((a, b) =>
a.priority.index.compareTo(b.priority.index) *
(sortOrder == SortOrder.Ascending ? 1 : -1));
break;
case '_currentSortOrderDueDate':
tasks.sort((a, b) =>
a.dueDate!.compareTo(b.dueDate!) *
(sortOrder == SortOrder.Ascending ? 1 : -1));
break;
case '_currentSortOrderFromDate':
tasks.sort((a, b) =>
a.fromDate!.compareTo(b.fromDate!) *
(sortOrder == SortOrder.Ascending ? 1 : -1));
break;
}
}
}
}
}
void _cycleSortOrder(TaskSortingCriteria sortingCriteria) {
setState(() {
switch (sortingCriteria) {
case TaskSortingCriteria.Priority:
sorting['_currentSortOrderPriority'][1] =
sorting['_currentSortOrderPriority'][1] == 'Ascending'
? 'Descending'
: 'Ascending';
switch (sorting['_currentSortOrderPriority'][0]) {
case 0:
sorting['_currentSortOrderPriority'][0] = 2;
sorting['_currentSortOrderDueDate'][0]--;
sorting['_currentSortOrderFromDate'][0]--;
break;
case 1:
sorting['_currentSortOrderPriority'][0] = 2;
if (sorting['_currentSortOrderDueDate'][0] == 2)
sorting['_currentSortOrderDueDate'][0] = 1;
else
sorting['_currentSortOrderFromDate'][0] = 1;
break;
case 2:
break;
}
break;
case TaskSortingCriteria.DueDate:
sorting['_currentSortOrderDueDate'][1] =
sorting['_currentSortOrderDueDate'][1] == 'Ascending'
? 'Descending'
: 'Ascending';
switch (sorting['_currentSortOrderDueDate'][0]) {
case 0:
sorting['_currentSortOrderDueDate'][0] = 2;
sorting['_currentSortOrderPriority'][0]--;
sorting['_currentSortOrderFromDate'][0]--;
break;
case 1:
sorting['_currentSortOrderDueDate'][0] = 2;
if (sorting['_currentSortOrderPriority'][0] == 2)
sorting['_currentSortOrderPriority'][0] = 1;
else
sorting['_currentSortOrderFromDate'][0] = 1;
break;
case 2:
break;
}
break;
case TaskSortingCriteria.FromDate:
sorting['_currentSortOrderFromDate'][1] =
sorting['_currentSortOrderFromDate'][1] == 'Ascending'
? 'Descending'
: 'Ascending';
switch (sorting['_currentSortOrderFromDate'][0]) {
case 0:
sorting['_currentSortOrderFromDate'][0] = 2;
sorting['_currentSortOrderPriority'][0]--;
sorting['_currentSortOrderDueDate'][0]--;
break;
case 1:
sorting['_currentSortOrderFromDate'][0] = 2;
if (sorting['_currentSortOrderPriority'][0] == 2)
sorting['_currentSortOrderPriority'][0] = 1;
else
sorting['_currentSortOrderDueDate'][0] = 1;
break;
case 2:
break;
}
break;
}
});
updateSorting();
sortTasks();
widget.onSort(tasks);
}
Future<void> updateSorting() async {
await _collectionRef.doc(taskTitle).set({
'sorting': toJson(),
}, SetOptions(merge: true));
}
Map<String, dynamic> toJson() {
return {
'_currentSortOrderPriority': {
sorting['_currentSortOrderPriority'][0],
sorting['_currentSortOrderPriority'][1],
},
'_currentSortOrderDueDate': {
sorting['_currentSortOrderDueDate'][0],
sorting['_currentSortOrderDueDate'][1],
},
'_currentSortOrderFromDate': {
sorting['_currentSortOrderFromDate'][0],
sorting['_currentSortOrderFromDate'][1],
},
};
}
Widget _buildSortButton(String label, TaskSortingCriteria sortingCriteria) {
print(sorting);
IconData icon;
switch (sortingCriteria) {
case TaskSortingCriteria.Priority:
icon = sorting['_currentSortOrderPriority'][1] == SortOrder.Ascending
? Icons.arrow_upward
: Icons.arrow_downward;
break;
case TaskSortingCriteria.DueDate:
icon = sorting['_currentSortOrderDueDate'][1] == SortOrder.Ascending
? Icons.arrow_upward
: Icons.arrow_downward;
break;
case TaskSortingCriteria.FromDate:
icon = sorting['_currentSortOrderFromDate'][1] == SortOrder.Ascending
? Icons.arrow_upward
: Icons.arrow_downward;
break;
default:
print('error');
icon = Icons.error;
}
return ElevatedButton.icon(
onPressed: () {
print('sorting by $sortingCriteria');
_cycleSortOrder(sortingCriteria);
},
icon: Icon(icon),
label: Text(label),
);
}
@override
Widget build(BuildContext context) {
setState(() {
tasks = widget.tasks;
});
return loading
? Center(child: CircularProgressIndicator())
:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildSortButton('Sort by Priority', TaskSortingCriteria.Priority),
SizedBox(width: 6),
_buildSortButton('Sort by Due Date', TaskSortingCriteria.DueDate),
SizedBox(width: 6),
_buildSortButton('Sort by From Date', TaskSortingCriteria.FromDate),
],
);
}
}
来自另一个小部件的 WIDGET_SORT 调用
class TasksList extends StatefulWidget {
late final String user;
late final String taskTitle;
TasksList({required this.user, required this.taskTitle});
@override
State<TasksList> createState() => _TasksListState();
}
class _TasksListState extends State<TasksList> {
List<Task> tasks = [];
Set<int> usedIds = Set();
late String taskTitle;
late final String user;
late CollectionReference _collectionRef;
@override
void initState() {
super.initState();
user = widget.user;
taskTitle = widget.taskTitle;
_collectionRef = FirebaseFirestore.instance
.collection('Users')
.doc(user)
.collection('Tasks');
initializeData();
initializeSorting();
}
Future<void> initializeSorting() async {
DocumentSnapshot querySnapshot = await _collectionRef.doc(taskTitle).get();
if (!querySnapshot.exists) {
print('Sorting does not exist. Creating one...');
await FirebaseFirestore.instance
.collection('Users')
.doc(user)
.collection('Tasks').doc(taskTitle).set
({
'sorting': {
'_currentSortOrderPriority': {2, 'Ascending'},
'_currentSortOrderDueDate': {0, 'Ascending'},
'_currentSortOrderFromDate': {1, 'Ascending'},
}
}, SetOptions(merge: true));
}
}
Future<void> initializeData() async {
List<Task> fetchedTasks = await initializeTasks();
initializeUsedIds(fetchedTasks);
}
void initializeUsedIds(List<Task> tasks) {
for (Task task in tasks) {
usedIds.add(task.id);
}
}
Future<List<Task>> initializeTasks() async {...}
Future<List<Task>> getDailyTasks() async {...}
void sortTasks(List<Task> sortedTasks){
setState(() {
this.tasks = sortedTasks;
});
}
@override
Widget build(BuildContext context) {
// print(tasks);
return Scaffold(
appBar: AppBar(
title: Text(taskTitle),
),
body: Column(
children: [
TaskSortWidget(onSort: sortTasks, user: user, taskTitle: taskTitle, tasks: tasks), //calling task sort
Expanded(
child: ListView.builder(
itemCount: tasks.length,
itemBuilder: (BuildContext context, int index) {
if (index == tasks.length) {
return Container();
}
//rest of code here
}
``
I can't see your full build code but I am assuming you are calling values that are meant to be fetched from your database in your build before the Future function is finished.
In this case you need to display your build conditionally when it is completed.