Flutter Stateful Widget调用sqlite取数函数显示null不更新如何解决?
问题根源
getCurrentAssetsData中的SQLite查询是异步IO操作,你直接在build阶段同步调用该函数时,数据库查询还未完成,函数就已经执行结束。你写的return语句仅在.then()回调内部生效,外层函数没有显式返回值,默认返回null,因此Text组件显示null。- 控制台能打印出正确值是因为异步回调执行时数据已经返回,但此时UI早已渲染完成,没有触发重新渲染,数据不会自动更新到组件上。
注意:不要在build方法中直接执行异步查询操作,build会随状态刷新频繁触发,会造成大量重复无用的数据库查询,严重影响性能。
修复方案
方案1:预加载所有数据后统一渲染(推荐)
先在State类中新增资产数据缓存,加载coin列表时同步查询每个coin的资产数据,全部加载完成后再刷新UI
class _CoinListState extends State<CoinList> { DbHelper helper = DbHelper(); List<Coin> coins; int count=0; // 新增缓存Map,key为coin id,value为对应资产展示字符串 Map<int, String> coinAssetsCache = {}; // 改造getData方法,用async/await避免回调地狱 void getData() async { await helper.initializeDb(); final coinResult = await helper.getCoin(); count = coinResult.length; List<Coin> tempCoins = []; coinAssetsCache.clear(); for(int i=0;i<count;i++){ Coin coin = Coin.fromObject(coinResult[i]); tempCoins.add(coin); // 逐个查询对应资产数据存入缓存 String assetsData = await getCurrentAssetsData(coin); coinAssetsCache[coin.id] = assetsData; } // 所有数据加载完成后统一刷新UI setState(() { coins = tempCoins; this.count = count; }); } // 改造getCurrentAssetsData为返回Future的异步函数 Future<String> getCurrentAssetsData(Coin coin) async { await helper.initializeDb(); final orderResult = await helper.getCoinOrder(coin); double totalCost = 0; double totalCount = 0; double totalCommission=0; for(int i=0;i<orderResult.length;i++){ CoinOrder order = CoinOrder.fromObject(orderResult[i]); totalCost += order.count * order.buyValue; totalCount += order.count; totalCommission+= order.commission; } String sData = "Avg: ${totalCost/totalCount} Investment: ${totalCost}"; debugPrint(sData); return sData; } // 修改Text组件取值逻辑,从缓存中取数据 title: Text(this.coins[position].coin.toString() + " Temp Data " + (coinAssetsCache[this.coins[position].id] ?? "加载中...")), }
方案2:用FutureBuilder逐行加载
如果不需要等所有数据加载完成再显示列表,可以给每个列表项单独套FutureBuilder实现逐行加载:
// 把原title的Text组件替换为FutureBuilder title: FutureBuilder<String>( future: getCurrentAssetsData(this.coins[position]), builder: (context, snapshot) { if(snapshot.connectionState == ConnectionState.done && snapshot.hasData) { return Text(this.coins[position].coin.toString() + " Temp Data " + snapshot.data!); } else if(snapshot.hasError) { return Text(this.coins[position].coin.toString() + " Temp Data 加载失败"); } return Text(this.coins[position].coin.toString() + " Temp Data 加载中..."); }, ),
内容的提问来源于stack exchange,提问作者uday
相关产品推荐
相关产品推荐

