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

Flutter Stream Provider更新变量后未提供数据流问题求助

问题分析

你的核心问题在于:FilterProvider作为ChangeNotifier,但你通过独立的async*函数生成Stream,每次调用filterFetchService()仅生成新Stream,而StreamProvider并未监听这个新Stream;同时ChangeNotifier的通知机制与StreamProvider没有联动,导致keyword更新后无法触发新数据请求和UI刷新。

解决方案

要实现keyword更新时自动触发数据请求并刷新UI,需让FilterProvider维护一个可订阅的持续Stream,当keyword变化时重新发起查询并将结果推入Stream,同时让StreamProvider监听这个Stream。

1. 重构FilterProvider,用StreamController管理Stream

import 'dart:async';
import 'package:flutter/foundation.dart';
// 导入你的其他依赖(qlclient、GetFiltersProductModel等)

class FilterProvider extends ChangeNotifier {
  String? _keyword;
  final StreamController<GetFiltersProductModel> _filterStreamController = StreamController<GetFiltersProductModel>.broadcast();
  Stream<GetFiltersProductModel> get filterStream => _filterStreamController.stream;

  // 初始化时加载默认数据
  FilterProvider() {
    _fetchProducts();
  }

  void updateKeyword(String value) {
    _keyword = value;
    _fetchProducts(); // keyword更新后立即触发新请求
    notifyListeners(); // 可选:若有依赖ChangeNotifier的Widget需同步刷新
  }

  Future<void> _fetchProducts() async {
    try {
      QueryResult queryResult = await qlclient.query(
        QueryOptions(
          document: gql(QueryDocument.filters),
          variables: {
            "productPrams": {
              "search": _keyword ?? "",
              "visibility": true,
              "approved": true,
            }
          },
        ),
      );
      Map<String, dynamic> data = queryResult.data as Map<String, dynamic>;
      var body = GetFiltersProductModel.fromJson(data);
      if (kDebugMode) {
        print(data);
      }
      _filterStreamController.add(body); // 将新结果推入Stream
    } catch (e) {
      if (kDebugMode) {
        print("请求出错: $e");
      }
      _filterStreamController.addError(e); // 推送错误状态到Stream
    }
  }

  // 销毁时关闭控制器,避免内存泄漏
  @override
  void dispose() {
    _filterStreamController.close();
    super.dispose();
  }
}

2. 正确配置StreamProvider

在Widget树中,让StreamProvider监听FilterProvider暴露的filterStream:

ChangeNotifierProvider(
  create: (context) => FilterProvider(),
  child: StreamProvider<GetFiltersProductModel>.value(
    value: context.watch<FilterProvider>().filterStream,
    initialData: GetFiltersProductModel(), // 设置初始默认数据
    child: YourProductListWidget(),
  ),
)

3. UI层实现搜索与数据展示

在搜索组件中触发keyword更新:

TextField(
  onChanged: (value) {
    context.read<FilterProvider>().updateKeyword(value);
  },
  decoration: InputDecoration(hintText: "搜索商品"),
)

在商品列表组件中通过StreamBuilder获取并展示数据:

StreamBuilder<GetFiltersProductModel>(
  stream: context.watch<FilterProvider>().filterStream,
  initialData: GetFiltersProductModel(),
  builder: (context, snapshot) {
    if (snapshot.hasError) {
      return Text("加载出错: ${snapshot.error}");
    }
    if (!snapshot.hasData) {
      return CircularProgressIndicator();
    }
    return ListView.builder(
      itemCount: snapshot.data?.products.length ?? 0,
      itemBuilder: (context, index) {
        return ListTile(title: Text(snapshot.data!.products[index].name));
      },
    );
  },
)
关键注意点
  • 复用同一个StreamController的Stream,确保订阅者能持续接收新数据,避免每次生成新Stream导致订阅失效。
  • 必须在FilterProvider销毁时关闭StreamController,防止内存泄漏。
  • 通过broadcast类型的StreamController支持多个Widget同时订阅Stream。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 10:55:14