Flutter:无obs变量时如何触发FutureBuilder组件刷新?
解决Flutter中FutureBuilder在数据更新时不重建的问题
问题根源
你当前的代码存在两个核心问题:
numbers是普通List<int>,不是GetX的RxList,修改列表内容时不会触发Obx的重建监听- 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
相关产品推荐
相关产品推荐

