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)
          },
    )