使用RxList时检测到GetX不当使用问题求助
GetX可观察列表使用异常解决
问题背景
我创建了一个可观察列表(Observable List),通过API获取数据存入其中,但在UI中使用Obx监听列表更新时无效,触发GetX不当使用检测异常。
控制器代码
class FeedsController extends GetxController { final Rx<List<Stories>> _stories = Rx<List<Stories>>([]); @override void onInit() { super.onInit(); getActiveStories(); } List<Stories> get getStories { return _stories.value; } Future<List<Stories>> getActiveStories() async { var url = Uri.parse(storiesURL); Map<String, Object> params = {'apikey': apiKey, 'userid': "8"}; await http.post(url, body: params).then((value) { StoriesResponse storiesResponse = storiesResponseFromJson(value.body); _stories.value = storiesResponse.stories; }).onError((error, stackTrace) { debugPrint('Error occurred while fetching stories response: ${error.toString()}'); }); return _stories.value; } }
UI展示代码
class _ActiveStoriesListState extends State<ActiveStoriesList> { List<Story> _currentUserStories = []; final FeedsController _feedsController = Get.find(); @override void initState() { Future.delayed(Duration.zero, fetchUserStories); super.initState(); } @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Active Stories', style: titleLargeTextStyle.copyWith(fontSize: 22, fontWeight: FontWeight.w600),), const SizedBox(height: 10), SizedBox( height: 100, child: Obx( () => ListView.builder( shrinkWrap: true, scrollDirection: Axis.horizontal, itemBuilder: (ctx, index) => ActiveStoriesWidget(story: _currentUserStories[index]), itemCount: _currentUserStories.length, ), )), ], ); } void fetchUserStories() async { List<Stories> stories = _feedsController.getStories; stories = stories.where((story) => story.userId == '8').toList(); _currentUserStories = stories[0].story; debugPrint('Active Stories Page: ${_currentUserStories.length}'); } }
示例JSON数据
{ "status": 200, "success": [ { "user_id": "4", "first_name": "Abu", "profileImage": "jayspur.com/RallyApp/public/uploads/userImages/…", "story": [ { "story": "jayspur.com/RallyApp/public/uploads/userStories/…", "addeddate": "2023-02-08 09:58:11" } ] } ] }
核心问题分析
_currentUserStories不是可观察变量:Obx仅监听Rx类型变量的变化,_currentUserStories是普通List,值更新不会触发UI重建。- 数据更新未同步:
fetchUserStories仅在initState执行一次,API异步返回数据后控制器的_stories更新,但过滤逻辑不会重新执行,UI无法获取最新数据。 - 索引越界风险:直接取
stories[0]未做非空判断,若过滤后列表为空会抛出异常。
解决方案
方案一:UI直接监听控制器的可观察变量
去掉本地维护的_currentUserStories,在Obx内部基于控制器的_stories实时过滤处理:
class _ActiveStoriesListState extends State<ActiveStoriesList> { final FeedsController _feedsController = Get.find(); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Active Stories', style: titleLargeTextStyle.copyWith(fontSize: 22, fontWeight: FontWeight.w600),), const SizedBox(height: 10), SizedBox( height: 100, child: Obx( () { List<Stories> filteredStories = _feedsController._stories.value .where((story) => story.userId == '8') .toList(); if (filteredStories.isEmpty) { return const Center(child: Text('No stories available')); } List<Story> currentUserStories = filteredStories[0].story; return ListView.builder( shrinkWrap: true, scrollDirection: Axis.horizontal, itemBuilder: (ctx, index) => ActiveStoriesWidget(story: currentUserStories[index]), itemCount: currentUserStories.length, ); }, )), ], ); } }
方案二:将本地变量改为可观察类型
若需本地维护过滤后的数据,将_currentUserStories改为Rx类型并监听控制器变量变化:
class _ActiveStoriesListState extends State<ActiveStoriesList> { final RxList<Story> _currentUserStories = RxList<Story>([]); final FeedsController _feedsController = Get.find(); @override void initState() { super.initState(); ever(_feedsController._stories, (List<Stories> newStories) { updateUserStories(newStories); }); } void updateUserStories(List<Stories> stories) { List<Stories> filtered = stories.where((s) => s.userId == '8').toList(); if (filtered.isNotEmpty) { _currentUserStories.assignAll(filtered[0].story); } else { _currentUserStories.clear(); } } @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Active Stories', style: titleLargeTextStyle.copyWith(fontSize: 22, fontWeight: FontWeight.w600),), const SizedBox(height: 10), SizedBox( height: 100, child: Obx( () => _currentUserStories.isEmpty ? const Center(child: Text('No stories available')) : ListView.builder( shrinkWrap: true, scrollDirection: Axis.horizontal, itemBuilder: (ctx, index) => ActiveStoriesWidget(story: _currentUserStories[index]), itemCount: _currentUserStories.length, ), )), ], ); } }
控制器优化建议
将_stories改为RxList更符合GetX使用习惯,同时提供可观察getter封装:
class FeedsController extends GetxController { final RxList<Stories> _stories = RxList<Stories>([]); RxList<Stories> get stories => _stories; @override void onInit() { super.onInit(); getActiveStories(); } Future<void> getActiveStories() async { var url = Uri.parse(storiesURL); Map<String, Object> params = {'apikey': apiKey, 'userid': "8"}; try { final response = await http.post(url, body: params); StoriesResponse storiesResponse = storiesResponseFromJson(response.body); _stories.assignAll(storiesResponse.stories); } catch (error) { debugPrint('Error occurred while fetching stories response: ${error.toString()}'); } } }
内容的提问来源于stack exchange,提问作者Sheraz Ali
相关产品推荐
相关产品推荐

