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

使用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" 
        } 
      ] 
    } 
  ] 
}

核心问题分析

  1. _currentUserStories不是可观察变量:Obx仅监听Rx类型变量的变化,_currentUserStories是普通List,值更新不会触发UI重建。
  2. 数据更新未同步:fetchUserStories仅在initState执行一次,API异步返回数据后控制器的_stories更新,但过滤逻辑不会重新执行,UI无法获取最新数据。
  3. 索引越界风险:直接取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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:05:20