我应该关闭 BehaviorSubject

如何解决我应该关闭 BehaviorSubject

我就是因为这个晚上睡不着

我正在使用我的 DataObjectListOptions<T> 类,它包含许多帮助我听来自 firestore 的数据并对数据应用过滤和任何自定义转换

我使用 BehaviorSubject<T> objectsData 使用 StreamBuilder 侦听 UI 上的数据

所以我的问题是:我应该在 DataObjectListOptions<T> 上创建一个 dispose 方法来关闭 objectsData BehaviorSubject 还是在所有 StreamBuilder 的订阅取消后自动发生?

>

数据对象列表选项:

abstract class BaseListOptions<L,U> {
  BaseListOptions({
    this.onLongPress,this.tap,this.empty,this.showNull = false,bool selectionMode = false,Stream<L>? itemsStream,L? items,Map<String,U>? selected,})  : assert(itemsStream != null || items != null),assert(showNull == false || (showNull == true && empty != null)),_selectionMode = BehaviorSubject<bool>.seeded(selectionMode),_selected = BehaviorSubject<Map<String,U>>.seeded(selected ?? {}),_objectsData = itemsStream != null
            ? (BehaviorSubject<L>()..addStream(itemsStream))
            : BehaviorSubject<L>.seeded(items!);

  final BehaviorSubject<L> _objectsData;
  BehaviorSubject<L> get objectsData => _objectsData;
  L? get items => _objectsData.value;

  final BehaviorSubject<bool> _selectionMode;
  BehaviorSubject<bool> get selectionMode => _selectionMode;
  bool? get selectionModeLatest => _selectionMode.value;

  final BehaviorSubject<Map<String,U>?> _selected;
  BehaviorSubject<Map<String,U>?> get selected => _selected;
  Map<String,U>? get selectedLatest => _selected.value;

  final void Function(U)? tap;
  final void Function(U)? onLongPress;

  final U? empty;
  final bool showNull;

  void selectAll();
  void selectNone() {
    if (!_selectionMode.requireValue) _selectionMode.add(true);
    _selected.add({});
  }

  void toggleSelected(U item);

  void select(U item);

  void deselect(U item);
}

class DataObjectListOptions<T extends DataObject>
    implements BaseListOptions<List<T>,T> {
  DataObjectListOptions({
    Widget Function(T,void Function(T)? onLongPress,void Function(T)? onTap,Widget? trailing,Widget? subtitle)?
        itemBuilder,this.onLongPress,Stream<List<T>>? itemsStream,List<T>? items,T>? selected,required Stream<String> searchQuery,List<T> Function(List<T>,String)? filter,_filter = (filter ??
            ((o,f) =>
                o.where((e) => filterString(e.name).contains(f)).toList())),_searchQuery = BehaviorSubject<String>()..addStream(searchQuery),T>>.seeded(selected ?? {}),originalObjectsData = itemsStream != null
            ? (BehaviorSubject<Map<String,T>>()
              ..addStream(itemsStream.map((l) => {for (final o in l) o.id: o})))
            : BehaviorSubject<Map<String,T>>.seeded(
                {for (final o in items!) o.id: o}),itemBuilder = (itemBuilder ??
            (i,Widget? subtitle) =>
                DataObjectWidget<T>(i,subtitle: subtitle,onLongPress:
                        onLongPress != null ? () => onLongPress(i) : null,onTap: onTap != null ? () => onTap(i) : null,trailing: trailing)) {
    buildItem = (i,{onLongPress,onTap,trailing,subtitle}) {
      return this.itemBuilder(i,onLongPress,subtitle);
    };
    _objectsData = (showNull
        ? BehaviorSubject<List<T>>.seeded([empty!])
        : BehaviorSubject<List<T>>())
      ..addStream(Rx.combineLatest2<String,T>,List<T>>(
          _searchQuery,originalObjectsData,(search,items) => search.isNotEmpty
              ? _filter(items.values.toList(),search)
              : items.values.toList()));
  }

  @override
  late BehaviorSubject<List<T>> _objectsData;
  @override
  BehaviorSubject<List<T>> get objectsData => _objectsData;
  @override
  List<T>? get items => objectsData.value;

  final BehaviorSubject<Map<String,T>> originalObjectsData;

  @override
  final BehaviorSubject<bool> _selectionMode;
  @override
  BehaviorSubject<bool> get selectionMode => _selectionMode;
  @override
  bool? get selectionModeLatest => _selectionMode.value;

  @override
  final BehaviorSubject<Map<String,T>> _selected;
  @override
  BehaviorSubject<Map<String,T>> get selected => _selected;
  @override
  Map<String,T>? get selectedLatest => _selected.value;

  final BehaviorSubject<String> _searchQuery;
  BehaviorSubject<String> get searchQuery => _searchQuery;
  String? get searchQueryLatest => _searchQuery.value;

  final List<T> Function(List<T>,String) _filter;
  @override
  final void Function(T)? tap;
  @override
  final void Function(T)? onLongPress;

  @override
  final T? empty;
  @override
  final bool showNull;

  final Widget Function(T,Widget? subtitle) itemBuilder;

  late final Widget Function(T,{void Function(T)? onLongPress,Widget? subtitle}) buildItem;

  @override
  void selectAll() {
    if (!_selectionMode.requireValue) _selectionMode.add(true);
    _selected.add({for (var item in _objectsData.requireValue) item.id: item});
  }

  @override
  void selectNone() {
    if (!_selectionMode.requireValue) _selectionMode.add(true);
    _selected.add({});
  }

  @override
  void toggleSelected(T item) {
    if (_selected.requireValue.containsKey(item.id)) {
      deselect(item);
    } else {
      select(item);
    }
  }

  @override
  void select(T item) {
    assert(!_selected.requireValue.containsKey(item.id));
    _selected.add({..._selected.requireValue,item.id: item});
  }

  @override
  void deselect(T item) {
    assert(_selected.requireValue.containsKey(item.id));
    _selected.add(_selected.requireValue..remove(item.id));
  }
}

String filterString(String s) => s.toLowerCase();

UI 中的示例用法:

class DataObjectList<T extends DataObject> extends StatefulWidget {
  const DataObjectList({Key? key,required this.options}) : super(key: key);

  final DataObjectListOptions<T> options;

  @override
  _ListState<T> createState() => _ListState<T>();
}

class _ListState<T extends DataObject> extends State<DataObjectList<T>>{

  @override
  Widget build(BuildContext context) {

    return StreamBuilder<List<T>>(
      stream: widget.options.objectsData,builder: (context,stream) {
        if (stream.hasError) return Center(child: ErrorWidget(stream.error!));
        if (!stream.hasData)
          return const Center(child: CircularProgressIndicator());

        final List<T> _data = stream.data!;
        if (_data.isEmpty) return const Center(child: Text('No data to show'));

        return ListView.builder(
          padding: const EdgeInsets.symmetric(horizontal: 6),cacheExtent: 200,itemCount: _data.length,itemBuilder: (context,i) //item builder...);
      },);
  }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res