flutter getx 状态管理(二)

283 阅读2分钟

getx状态管理(一)中使用0.obs Obx(()=>Text(""))实现UI自动响应数据的变化,

现在来看第二种实现方式数据监听.

GetBuilder + update手动更新

class TestController extends GetxController {
  int count = 0;

  increment() {
    count++;
    update();
  }
}

class TestWidget extends GetView<TestController> {
  @override
  Widget build(BuildContext context) {
    return GetBuilder<TestController>(
        builder: (controller) => Text("${controller.count}"));
  }
}

GetBuilder 添加监听 刷新页面

@override
void initState() {
  super.initState();
  //controller 注册
  ...  
  //添加监听
  _subscribeToController();
}

void _subscribeToController() {
    //如果存在,先移除
   _remove?.call();  
  _remove = (widget.id == null)
      ? controller?.addListener(
          _filter != null ? _filterUpdate : getUpdate,
        )
      : controller?.addListenerId(
          widget.id,
          _filter != null ? _filterUpdate : getUpdate,
        );
}

@override
void dispose() {
  super.dispose();
  widget.dispose?.call(this);
  if (_isCreator! || widget.assignId) {
    if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) {
      GetInstance().delete<T>(tag: widget.tag);
    }
  }
  _remove?.call();
  controller = null;
  _isCreator = null;
  _remove = null;
  _filter = null;
}

//刷新页面
mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> {
  //如果element存在,调用 setState((){})刷新页面  
  void getUpdate() {
    if (mounted) setState(() {});
  }
}

controller.update() 更新数据

GetxController

abstract class GetxController extends DisposableInterface with ListenableMixin, ListNotifierMixin
  
  //ids 更新有id的widget, condition 更新条件
  void update([List<Object>? ids, bool condition = true]) {
    if (!condition) {
      return;
    }
    if (ids == null) {
      refresh();
    } else {
      for (final id in ids) {
        refreshGroup(id);
      }
    }
  }
}

GetxController with ListNotifierMixin

1. addListener 添加监听到_updaters中并返回一个移除监听的Function

2. refresh 执行_updaters中的方法 3. 执行getUpdate setState()执行build()

4. removeListener 移除监听

mixin ListNotifierMixin on ListenableMixin {
  
  //监听列表  
  List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[];

  HashMap<Object?, List<GetStateUpdate>>? _updatersGroupIds =
      HashMap<Object?, List<GetStateUpdate>>();
  
  ///1.
  @protected
  void refresh() {
    _notifyUpdate();
  }
  //2.刷新所有添加监听的widget  
  void _notifyUpdate() {
    for (var element in _updaters!) {
      element!();
    }
  }
   //3.刷新特定id的widget 
  void _notifyIdUpdate(Object id) {
    if (_updatersGroupIds!.containsKey(id)) {
      final listGroup = _updatersGroupIds![id]!;
      for (var item in listGroup) {
        item();
      }
    }
  }

  @protected
  void refreshGroup(Object id) {
    _notifyIdUpdate(id);
  }

    
  @protected
  void notifyChildrens() {
    TaskManager.instance.notify(_updaters);
  }
    
  bool get hasListeners {
    assert(_debugAssertNotDisposed());
    return _updaters!.isNotEmpty;
  }

  int get listeners {
    assert(_debugAssertNotDisposed());
    return _updaters!.length;
  }
  
  //移除监听
  @override
  void removeListener(VoidCallback listener) {
    assert(_debugAssertNotDisposed());
    _updaters!.remove(listener);
  }

  void removeListenerId(Object id, VoidCallback listener) {
    assert(_debugAssertNotDisposed());
    if (_updatersGroupIds!.containsKey(id)) {
      _updatersGroupIds![id]!.remove(listener);
    }
    _updaters!.remove(listener);
  }

  @mustCallSuper
  void dispose() {
    assert(_debugAssertNotDisposed());
    _updaters = null;
    _updatersGroupIds = null;
  }
  
  /// GetBuild 添加监听
  // 返回一个移除监听的Function
  @override
  Disposer addListener(GetStateUpdate listener) {
    assert(_debugAssertNotDisposed());
    _updaters!.add(listener);
    return () => _updaters!.remove(listener);
  }

  Disposer addListenerId(Object? key, GetStateUpdate listener) {
    _updatersGroupIds![key] ??= <GetStateUpdate>[];
    _updatersGroupIds![key]!.add(listener);
    return () => _updatersGroupIds![key]!.remove(listener);
  }

  /// To dispose an [id] from future updates(), this ids are registered
  /// by `GetBuilder()` or similar, so is a way to unlink the state change with
  /// the Widget from the Controller.
  void disposeId(Object id) {
    _updatersGroupIds!.remove(id);
  }
}