Flutter - 如何获取变量中需要 'await' 的提供程序调用函数的值?
Flutter - How to get the value of a provider call function that requires 'await' within a variable?
我正在尝试制作一个预算应用程序,其中每个预算都有自己的支出历史记录。这些支出历史记录中的每一个都有一个名为 'budgetName' 的变量,我可以使用如下 sqflite 代码编译和计算支出总额。
return await db.rawQuery("select sum(budgetSpent) as total from spending where budgetName ='" + budgetTitle + "'");
如果我在调用 sqflite 函数时尝试使用 .then((value) {print(value);})
并在调试控制台中查看每个预算支出的值,则此方法有效。
但问题是我在调用函数时需要 'budgetTitle' 以便它可以与支出的 'budgetName' 进行比较以获得总支出金额。
所以我现在所拥有的是尝试获得如下支出金额:
child: BudgetCard(
budgetName: budget.budgetName,
budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}',
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5),
),
但它只有 returns Instance of 'Future<dynamic>'
因为它在获取值之前需要 'await'。但是我找不到另一种方法,因为它需要传递 'budgetTitle'。
非常感谢任何帮助、想法或建议!提前谢谢你。
这里是数据库代码:
String? budgetSpendingAmount;
getSpecificSpending(budgetTitle) async {
dynamic result =
await SpendingDatabaseHelper.instance.getSpendingAmount(budgetTitle);
String a = result.toString();
debugPrint('A: $a');
if (a == '[{total: null}]') {
a = currency.format(int.parse('000'.trim()));
budgetSpendingAmount = a;
print(budgetSpendingAmount);
} else {
String? b = a.replaceAll(RegExp(r'[{\}\[\]\-]+'), '');
String c = b.substring(b.indexOf(":") + 1);
budgetSpendingAmount = currency.format(int.parse(c.trim()));
}
notifyListeners();
}
Future getSpendingAmount(String budgetTitle) async {
Database db = await instance.database;
return await db.rawQuery("select sum(budgetSpent) as total from spending where ='" + budgetTitle + "'");
}
以下是我调用函数获取消费金额数据的完整代码:
Widget build(BuildContext context) {
return FutureBuilder<List<Budget>>(
future: Provider.of<BudgetDatabaseHelper>(context).getBudgets(),
/// Displaying the data from the list
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center();
}
return snapshot.data!.isEmpty
? const Flexible(
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 80.0),
child: Text(
'You don\'t have any budget',
style: kCaption,
),
)))
: Flexible(
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final budget = snapshot.data![index];
return Dismissible(
key: UniqueKey(),
background: const Align(
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.only(bottom: 12.0, right: 24),
child: Icon(
IconlyLight.delete,
color: cRed,
size: 24,
),
),
),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
snapshot.data!.removeAt(index);
Provider.of<BudgetDatabaseHelper>(context,
listen: false)
.removeMethod(budget.id!, budget.budgetName);
},
child: GestureDetector(
onTap: () => showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
enableDrag: true,
isScrollControlled: true,
builder: (context) {
return DraggableScrollableSheet(
snap: true,
minChildSize: 0.43,
maxChildSize: 0.85,
initialChildSize: 0.43,
snapSizes: const [0.43, 0.85],
builder: (context, scrollController) {
return ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32)),
child: Container(
color: cWhite,
child: SingleChildScrollView(
controller: scrollController,
physics: const BouncingScrollPhysics(),
child: BudgetDetails(
id: budget.id!,
budgetName: budget.budgetName,
budgetSpent: 'budgetSpent',
colorValue:
colorSwatch[budget.colorValue],
maxBudget: currency.format(
int.parse(budget.maxBudget)),
svgIcon: iconListBudgetDetails[
budget.iconValue],
),
),
),
);
},
);
},
),
child: BudgetCard(
budgetName: budget.budgetName,
budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}',
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5),
),
);
},
),
);
},
);
}
一些想法
在 BudgetCard 小部件中使用 FutureBuilder。然后,当您仍在等待未来完成时,您可以显示一个 CircularProgressIndicator,其中花费的金额。
或
使用布尔标志(在 future 方法的开头和结尾翻转)来指示 future 是否已完成。标记 false:显示进度指示器,标记 true 显示花费的金额。
或
调用 Provider.of<BudgetDatabaseHelper>(context).getBudgets()
时,您可以让方法 getBudgets()
也用稍后需要的信息填充一个数组。因此,在 getBudgets()
方法中为您拥有的每个 budgetName 调用 Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName)
。
在小部件树中使用 provider
不是一个好主意。做一个statefullWidget
像这样在 SpendingDatabaseHelper
中创建一个 getter
String? _budgetSpendingAmount;
String get budgetSpendingAmount=> _budgetSpendingAmount;
并像这样初始化它_budgetSpendingAmount = currency.format(int.parse(c.trim()));
所以使用这个 getter 你可以在小部件树中的任何地方访问这个值
Future<void> _getSpecificSpending(String budgetName)async{
try{
await Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budgetName);
} catch(e){
print('error :$e');
}
}
然后在你的小部件树中写下这样的东西
child: FutureBuilder(
future : _getSpecificSpending(budget.budgetName)
builder: (ctx,snapshot){
var spendDataProv=Provider.of<SpendingDatabaseHelper>(context, listen: false);
return snapshot.connectionState==ConnectionState.waiting ?
CircularProgressIndicator() :
BudgetCard(
budgetName: budget.budgetName,
budgetSpent:spendDataProv.budgetSpendingAmount ,
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5)
},
)
我正在尝试制作一个预算应用程序,其中每个预算都有自己的支出历史记录。这些支出历史记录中的每一个都有一个名为 'budgetName' 的变量,我可以使用如下 sqflite 代码编译和计算支出总额。
return await db.rawQuery("select sum(budgetSpent) as total from spending where budgetName ='" + budgetTitle + "'");
如果我在调用 sqflite 函数时尝试使用 .then((value) {print(value);})
并在调试控制台中查看每个预算支出的值,则此方法有效。
但问题是我在调用函数时需要 'budgetTitle' 以便它可以与支出的 'budgetName' 进行比较以获得总支出金额。
所以我现在所拥有的是尝试获得如下支出金额:
child: BudgetCard(
budgetName: budget.budgetName,
budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}',
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5),
),
但它只有 returns Instance of 'Future<dynamic>'
因为它在获取值之前需要 'await'。但是我找不到另一种方法,因为它需要传递 'budgetTitle'。
非常感谢任何帮助、想法或建议!提前谢谢你。
这里是数据库代码:
String? budgetSpendingAmount;
getSpecificSpending(budgetTitle) async {
dynamic result =
await SpendingDatabaseHelper.instance.getSpendingAmount(budgetTitle);
String a = result.toString();
debugPrint('A: $a');
if (a == '[{total: null}]') {
a = currency.format(int.parse('000'.trim()));
budgetSpendingAmount = a;
print(budgetSpendingAmount);
} else {
String? b = a.replaceAll(RegExp(r'[{\}\[\]\-]+'), '');
String c = b.substring(b.indexOf(":") + 1);
budgetSpendingAmount = currency.format(int.parse(c.trim()));
}
notifyListeners();
}
Future getSpendingAmount(String budgetTitle) async {
Database db = await instance.database;
return await db.rawQuery("select sum(budgetSpent) as total from spending where ='" + budgetTitle + "'");
}
以下是我调用函数获取消费金额数据的完整代码:
Widget build(BuildContext context) {
return FutureBuilder<List<Budget>>(
future: Provider.of<BudgetDatabaseHelper>(context).getBudgets(),
/// Displaying the data from the list
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center();
}
return snapshot.data!.isEmpty
? const Flexible(
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 80.0),
child: Text(
'You don\'t have any budget',
style: kCaption,
),
)))
: Flexible(
child: ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final budget = snapshot.data![index];
return Dismissible(
key: UniqueKey(),
background: const Align(
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.only(bottom: 12.0, right: 24),
child: Icon(
IconlyLight.delete,
color: cRed,
size: 24,
),
),
),
direction: DismissDirection.endToStart,
onDismissed: (direction) {
snapshot.data!.removeAt(index);
Provider.of<BudgetDatabaseHelper>(context,
listen: false)
.removeMethod(budget.id!, budget.budgetName);
},
child: GestureDetector(
onTap: () => showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
enableDrag: true,
isScrollControlled: true,
builder: (context) {
return DraggableScrollableSheet(
snap: true,
minChildSize: 0.43,
maxChildSize: 0.85,
initialChildSize: 0.43,
snapSizes: const [0.43, 0.85],
builder: (context, scrollController) {
return ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32)),
child: Container(
color: cWhite,
child: SingleChildScrollView(
controller: scrollController,
physics: const BouncingScrollPhysics(),
child: BudgetDetails(
id: budget.id!,
budgetName: budget.budgetName,
budgetSpent: 'budgetSpent',
colorValue:
colorSwatch[budget.colorValue],
maxBudget: currency.format(
int.parse(budget.maxBudget)),
svgIcon: iconListBudgetDetails[
budget.iconValue],
),
),
),
);
},
);
},
),
child: BudgetCard(
budgetName: budget.budgetName,
budgetSpent: '${Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName}',
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5),
),
);
},
),
);
},
);
}
一些想法
在 BudgetCard 小部件中使用 FutureBuilder。然后,当您仍在等待未来完成时,您可以显示一个 CircularProgressIndicator,其中花费的金额。
或
使用布尔标志(在 future 方法的开头和结尾翻转)来指示 future 是否已完成。标记 false:显示进度指示器,标记 true 显示花费的金额。
或
调用 Provider.of<BudgetDatabaseHelper>(context).getBudgets()
时,您可以让方法 getBudgets()
也用稍后需要的信息填充一个数组。因此,在 getBudgets()
方法中为您拥有的每个 budgetName 调用 Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budget.budgetName)
。
在小部件树中使用 provider
不是一个好主意。做一个statefullWidget
像这样在 SpendingDatabaseHelper
中创建一个 getter
String? _budgetSpendingAmount;
String get budgetSpendingAmount=> _budgetSpendingAmount;
并像这样初始化它_budgetSpendingAmount = currency.format(int.parse(c.trim()));
所以使用这个 getter 你可以在小部件树中的任何地方访问这个值
Future<void> _getSpecificSpending(String budgetName)async{
try{
await Provider.of<SpendingDatabaseHelper>(context, listen: false).getSpecificSpending(budgetName);
} catch(e){
print('error :$e');
}
}
然后在你的小部件树中写下这样的东西
child: FutureBuilder(
future : _getSpecificSpending(budget.budgetName)
builder: (ctx,snapshot){
var spendDataProv=Provider.of<SpendingDatabaseHelper>(context, listen: false);
return snapshot.connectionState==ConnectionState.waiting ?
CircularProgressIndicator() :
BudgetCard(
budgetName: budget.budgetName,
budgetSpent:spendDataProv.budgetSpendingAmount ,
maxBudget: currency.format(int.parse(budget.maxBudget)),
svgIcon: iconListBudgetCards[budget.iconValue],
color: colorSwatch[budget.colorValue],
percentage: 0.5)
},
)