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

Flutter:无obs变量时如何触发FutureBuilder组件刷新?

解决Flutter中FutureBuilder在数据更新时不重建的问题

问题根源

你当前的代码存在两个核心问题:

  1. numbers是普通List<int>,不是GetX的RxList,修改列表内容时不会触发Obx的重建监听
  2. Obx内部没有绑定任何可观察的obs变量,导致数据更新时无法触发FutureBuilder重新执行

方案一:将全局列表改为RxList并监听(保留原结构)

1. 修改数据源代码

把普通列表替换为GetX的可观察列表:

import 'package:get/get.dart';

RxList<int> numbers = [1,2,3].obs;

2. 调整DataController的fetchData方法

确保返回最新的列表数据,同时保留异步模拟逻辑:

class DataController extends GetxController {
  RxBool isLoading = false.obs;

  Future<List<int>> fetchData() async {
    try {
      isLoading.value = true;
      // 模拟异步操作(比如网络请求)
      await Future.delayed(const Duration(milliseconds: 300));
      return numbers.toList();
    } catch (e) {
      print('Something wrong: $e');
      return [];
    } finally {
      isLoading.value = false;
    }
  }
}

3. 修改Widget中的Obx监听

让Obx监听numbers这个可观察列表,触发FutureBuilder重建:

Widget build(BuildContext context) {
  final controller = Get.put(DataController());
  return Scaffold(
    body: Column(
      children: [
        Expanded(
          child: Obx(
            () => FutureBuilder(
              future: controller.fetchData(),
              builder: (context, snapshot) {
                const loader = Center(child: CircularProgressIndicator());

                if (snapshot.connectionState == ConnectionState.waiting)
                  return loader;

                if (!snapshot.hasData ||
                    snapshot.data == null ||
                    snapshot.data!.isEmpty)
                  return const Center(child: Text('No data found'));

                if (snapshot.hasError) {
                  return const Center(child: Text('Error found'));
                }

                final allData = snapshot.data!;
                return ListView.builder(
                  shrinkWrap: true,
                  itemCount: allData.length,
                  itemBuilder: (context, index) {
                    final data = allData[index];
                    return ListTile(title: Text(data.toString()));
                  },
                );
              },
            ),
          ),
        ),
        SizedBox(
          height: 100,
          width: double.infinity,
          child: ElevatedButton(
            onPressed: () {
              final num = Random().nextInt(1000);
              numbers.add(num); // RxList的add方法会自动触发监听更新
            },
            child: const Text('Add Number'),
          ),
        )
      ],
    ),
  );
}

方案二:将列表移至Controller管理(更符合GetX架构)

这种方式避免全局变量,统一由Controller管理数据,更易维护:

1. 重构DataController

把numbers移到Controller内部并改为RxList,同时添加添加数据的方法:

class DataController extends GetxController {
  RxBool isLoading = false.obs;
  RxList<int> numbers = [1,2,3].obs;

  Future<List<int>> fetchData() async {
    try {
      isLoading.value = true;
      await Future.delayed(const Duration(milliseconds: 300));
      return numbers.toList();
    } catch (e) {
      print('Something wrong: $e');
      return [];
    } finally {
      isLoading.value = false;
    }
  }

  void addRandomNumber() {
    final num = Random().nextInt(1000);
    numbers.add(num);
  }
}

2. 修改Widget代码

Obx监听Controller的numbers,按钮点击直接调用Controller的方法:

Widget build(BuildContext context) {
  final controller = Get.put(DataController());
  return Scaffold(
    body: Column(
      children: [
        Expanded(
          child: Obx(
            () => FutureBuilder(
              future: controller.fetchData(),
              builder: (context, snapshot) {
                const loader = Center(child: CircularProgressIndicator());

                if (snapshot.connectionState == ConnectionState.waiting)
                  return loader;

                if (!snapshot.hasData ||
                    snapshot.data == null ||
                    snapshot.data!.isEmpty)
                  return const Center(child: Text('No data found'));

                if (snapshot.hasError) {
                  return const Center(child: Text('Error found'));
                }

                final allData = snapshot.data!;
                return ListView.builder(
                  shrinkWrap: true,
                  itemCount: allData.length,
                  itemBuilder: (context, index) {
                    final data = allData[index];
                    return ListTile(title: Text(data.toString()));
                  },
                );
              },
            ),
          ),
        ),
        SizedBox(
          height: 100,
          width: double.infinity,
          child: ElevatedButton(
            onPressed: () => controller.addRandomNumber(),
            child: const Text('Add Number'),
          ),
        )
      ],
    ),
  );
}

优化建议:移除FutureBuilder(本地数据场景)

如果你的fetchData只是模拟异步,实际是本地数据,完全可以不用FutureBuilder,直接用Obx包裹ListView,性能更优:

Expanded(
  child: Obx(() {
    if (controller.isLoading.value) {
      return const Center(child: CircularProgressIndicator());
    }
    if (controller.numbers.isEmpty) {
      return const Center(child: Text('No data found'));
    }
    return ListView.builder(
      shrinkWrap: true,
      itemCount: controller.numbers.length,
      itemBuilder: (context, index) {
        final data = controller.numbers[index];
        return ListTile(title: Text(data.toString()));
      },
    );
  }),
),

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 14:47:09