我一直在努力解决数据流和状态管理问题,特别是使用提供程序包。我尝试使用Future
从firestore查询,但事实证明,由于Future
仅期望一个值,因此不能充分利用firestore的功能。
因此,我改用Stream
代替,而使用StreamProvider
将数据获取到我的小部件。问题是我不知道在什么时候/如何告诉UI重建。有时流中有数据,有时却没有,我也无法真正分辨出这段时间内发生了什么。假设我想在视图繁忙时显示一个圆形进度条,那么在使用StreamProvider
时该如何实现。这样做甚至有意义吗?
因此,通过filledstacks方法,当使用期货进行网络通话时,人们可以在繁忙和空闲之间切换模型状态。例如,当我们调用getPosts
方法时,我们首先将状态设置为Busy,以便UI可以做出反应并可能显示加载指示符。但是,一旦异步接收到数据,我们可以将状态设置回空闲。另一方面,至少从我的理解来看,Stream
只是一个不断传递数据的管道,我无法提出一种实现忙/闲状态或什至不知道这种{{ 1}}有新数据/任何数据。有什么想法吗?
这是我的Stream
的一部分,应该从Firestore返回数据流。
database_service.dart
这是我的Stream<List<Expense>> getExpenses(int month, int year) {
var ref = _db
.collection("userData")
.document(fireUser.uid)
.collection("expenses")
.where("month", isEqualTo: month)
.where("year", isEqualTo: year)
.orderBy("date", descending: true);
return ref.snapshots().map((list) =>
list.documents.map((snap) => Expense.fromFirestore(snap)).toList());
}
使用expenses.dart
的视图文件的一部分。
StreamProvider
和class ExpensesPage extends StatefulWidget {
@override
_ExpensesPageState createState() => _ExpensesPageState();
}
class _ExpensesPageState extends State<ExpensesPage> {
int _month;
int _year;
@override
void initState() {
super.initState();
_month = DateTime.now().month;
_year = DateTime.now().year;
}
@override
Widget build(BuildContext context) {
return StreamProvider<List<Expense>>.value(
stream: locator<ExpensesProvider>().getMonthExpenses(_month, _year),
initialData: [],
child: StreamProvider<List<Category>>.value(
stream: locator<ExpensesProvider>().getCategories(),
initialData: [],
child: Scaffold(
body: Container(
alignment: Alignment.center,
color: Theme.of(context).primaryColor,
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
child: DateHeader("$_month $_year"),
onTap: () => _selectDate(),
),
Expanded(
child: ExpenseList(
month: _month,
year: _year,
),
)
],
),
),
),
),
);
}
和expense_list.dart
小部件使用ExpenseList
中的数据。
StreamProvider
我的UI一直处于这种状态
,即使我希望它会与class ExpenseList extends StatelessWidget {
final _dateFormat = DateFormat.yMMMEd();
final _dbService = locator<DatabaseService>();
final int month;
final int year;
ExpenseList({@required this.month, @required this.year});
String getMonthName(int month) {
return _dbService.monthNames[month - 1];
}
@override
Widget build(BuildContext context) {
var expenses = Provider.of<List<Expense>>(context);
var categories = Provider.of<List<Category>>(context);
return expenses.length < 1
? Center(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"You do not have any expenses for ${getMonthName(month)}, $year",
style: Theme.of(context).textTheme.subhead,
textAlign: TextAlign.center,
),
),
)
: ListView.builder(
itemBuilder: (BuildContext context, int index) {
var cat = categories.firstWhere(
(category) => category.id == expenses[index].category,
orElse: () => Category.initial(),
);
var sub = cat.subs[expenses[index].subcategory];
var amount = expenses[index].amount;
var date = expenses[index].date;
return ExpenseCard(
expenseCategory: cat.name,
expenseSubCategory: sub,
expenseAmount: amount,
expenseDate: _dateFormat.format(date),
cardColor: Theme.of(context).cardColor);
},
itemCount: expenses.length,
);
}
}
中的数据一起更新。