我应该关闭 BehaviorSubject

问题描述

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

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

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

所以我的问题是:我应该在 DataObjectListOptions<T> 上创建一个 @R_502_6422@pose 方法关闭 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 (将#修改为@)