You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Image Picker retrieveLostData触发StreamBuilder频繁显示加载页问题

问题根源

  1. 你在FutureBuilder的future参数中直接传入了retrieveLostData(),这会导致每次页面触发build时,都会重新执行这个异步方法,生成全新的Future实例,FutureBuilder会反复进入等待状态,流程执行完成后又重新创建myPage组件。
  2. myPage被反复销毁重建时,内部的StreamBuilder会重新监听数据库stream,每次重新订阅都会短暂进入ConnectionState.waiting状态,触发加载UI的显示。
  3. 你的retrieveLostData方法存在空安全隐患:当response.file为空时,你直接用!强解response.exception,如果此时没有异常(也就是exception也为空),就会抛出空指针异常,导致Future执行失败,触发页面再次重建,形成死循环。

修复步骤

1. 缓存Future实例,避免重复执行

在页面的State类中,提前初始化retrieveLostData的Future,不要在build方法里创建:

late final Future<void> _retrieveLostDataFuture;

@override
void initState() {
  super.initState();
  // 仅在页面初始化时执行一次retrieveLostData
  _retrieveLostDataFuture = retrieveLostData();
}

然后把FutureBuilder的future参数替换为这个缓存的实例:

future: _retrieveLostDataFuture,

2. 修复retrieveLostData的空安全问题

修改异常处理逻辑,只有确认exception不为空时再写入日志:

Future<void> retrieveLostData() async {
    print("Retrieve Lost Data ${DateTime.now()}");
    final LostDataResponse response = await CustomImagePicker.imagePicker.retrieveLostData();
 
    if (response.file != null) {
      if (response.type == RetrieveType.video) {
        // 视频逻辑预留
      } else {
        _savePicture(response.file!);
      }
    } else if (response.exception != null) {
      // 只有存在异常时才处理
      String retrieveDataError = response.exception!.code;
      LogsCompanion log = LogsCompanion.insert(message: "IMAGE PROBLEM: ${retrieveDataError}", date: DateTime.now());
      _appDatabase.logDao.insertLog(log);
    }
}

3. 优化StreamBuilder的判断逻辑(可选)

你已经给StreamBuilder设置了initialData: [],正常情况下不会出现无数据同时处于waiting状态的情况,调整判断顺序可以避免不必要的加载显示:

StreamBuilder(
  initialData: [],
  stream: _appDatabase.myDao.getStream(),
  builder: (context, snapshot) {
    // 优先处理异常
    if (snapshot.hasError) {
      return Text('加载失败:${snapshot.error}');
    }
    // 有数据直接渲染,不管连接状态
    final list = snapshot.data as List;
    if (list.isNotEmpty) {
      return ListView.separated(
        separatorBuilder: (context, index) => Container(height: 8),
        physics: BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
        itemCount: list.length,
        itemBuilder: (context, index) {
          return Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              listItem(list[index]),
            ],
          );
        },
      );
    }
    // 空列表时返回下拉刷新组件
    return RefreshIndicator(
      onRefresh: () async {},
      child: const Center(child: Text('暂无数据')),
    );
  },
),

修改完成后retrieveLostData只会在页面初始化时执行一次,不会反复触发页面重建,StreamBuilder也不会被反复销毁重建,循环就会停止。


内容的提问来源于stack exchange,提问作者SaddleMantle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 00:39:05