我们封装了哪些好用的Flutter Mixin

一、Mixin 的本质

  • 定义 :Mixin 是一种特殊的类,通过 mixin 关键字声明,不能直接实例化,但可以被其他类"混入"(使用 with 关键字)。

  • 核心思想:将可复用的代码片段注入到多个不相关的类中,实现代码的横向组合(而非纵向继承)。

二、Mixin 的工作原理

  • 线性化(Linearization) :Dart 使用线性化算法处理混入顺序。当多个 Mixin 存在时,它们的属性和方法会按 with 的声明顺序从右到左叠加(最后混入的优先级最高)。

    Dart 复制代码
    class MyWidget with MixinA, MixinB, MixinC {}
    // 方法解析顺序:MixinC → MixinB → MixinA → MyWidget
  • 冲突解决:如果多个 Mixin 有同名方法,后混入的会覆盖前面的(类似"最后一个生效"规则)。

三、Mixin vs 继承 vs 接口

特性 Mixin 继承 (extends) 接口 (implements)
复用方式 横向组合 纵向继承 强制实现契约
多重支持 是(with A,B 否(单继承)
代码复用 直接复用逻辑 复用父类实现 无默认实现
典型场景 跨类共享工具方法 "is-a"关系 "can-do"能力

四、我们在项目中封装哪些Mixin

1、AddListenerMixin

Dart 复制代码
mixin AddListenerMixin<T extends StatefulWidget> on State<T> {
  final Map<Listenable, VoidCallback> _registrationInfo = {};

  void addListener(Listenable listenable, VoidCallback listener) {
    listenable.addListener(listener);
    _registrationInfo[listenable] = listener;
  }

  @override
  void dispose() {
    for (var entry in _registrationInfo.entries) {
      entry.key.removeListener(entry.value);
    }
    _registrationInfo.clear();
    super.dispose();
  }
}

项目中使用的** AddListenerMixin 主要是简化 Listenable 对象(如 ValueNotifierAnimationController **等)的监听管理,自动处理监听器的注册和清理,避免内存泄漏。同时也可以减少dispose时的样板代码。

不过目前AddListenerMixin 不支持手动移除VoidCallback,也不支持批量操作。

2、SafeSetStateMixin

Dart 复制代码
mixin SafeSetStateMixin<T extends StatefulWidget> on State<T> {
  
  void safeSetState(VoidCallback fn) {
    fn.call();
    if (!mounted) return;
    final animStatus = ModalRoute.of(context)?.animation?.status;
    if (animStatus == null || animStatus == AnimationStatus.completed) {
      scheduleMicrotask(() {
        if (mounted) {
          setState(() {});
        }
      });
    } else {
      _listenRouteAnim();
      _needSetState = true;
    }
  }

  Animation? _routeAnim;
  bool _needSetState = false;

  void _listenRouteAnim() {
    _routeAnim?.removeStatusListener(_animStatusListener);
    _routeAnim = ModalRoute.of(context)?.animation;
    _routeAnim?.addStatusListener(_animStatusListener);
  }

  @override
  void deactivate() {
    _routeAnim?.removeStatusListener(_animStatusListener);
    _routeAnim = null;
    super.deactivate();
  }

  void _animStatusListener(AnimationStatus status) {
    if (_needSetState && status == AnimationStatus.completed) {
      _needSetState = false;
      safeSetState(() {});
    }
  }
}

SafeSetStateMixin 的作用

  • 避免在disposed状态下调用setState

  • 避免在动画未完成的情况下触发setState,通过监听动画状态,在动画完成后及时触发setState更新

  • 异步安全,通过 scheduleMicrotask 延迟 setState,避免在 build 过程中同步触发更

3、StreamControlMixin

Dart 复制代码
mixin StreamControlMixin<T extends StatefulWidget> on State<T> {
  final Set<StreamSubscription> _subscriptions = {};

  void addSubscription(StreamSubscription subscription) {
    if (subscription != null) {
      _subscriptions.add(subscription);
    }
  }

  bool removeSubscription(StreamSubscription subscription) {
    if (subscription != null) {
      return _subscriptions.remove(subscription);
    }
    return false;
  }

  void cancelAllEvents() {
    for (var subscription in _subscriptions) {
      try {
        subscription.cancel();
      } catch (e) {
        debugPrint('Error canceling subscription: $e');
      }
    }
    _subscriptions.clear();
  }

  bool hasSubscription(StreamSubscription subscription) {
    return _subscriptions.contains(subscription);
  }

  @override
  void dispose() {
    if (_subscriptions.isNotEmpty) {
      cancelAllEvents();
    }
    super.dispose();
  }
}

StreamControlMixin的作用

  • 提供统一的方式来管理StreamSubscription,支持手动添加、移除

  • 自动清理资源,在组件销毁时自动取消所有订阅,防止内存泄漏

  • 简化添加、移除流程,减少模版代码

五、总结

本篇主要是简单介绍了一下Mixin,总结分享了一下在项目我们封装了哪些Mixin,希望能够给读者带来一些思考。实际上个人认为封装的中心思想都是一致,仅是利用不同语言的特性。

相关推荐
计蒙不吃鱼5 小时前
一篇文章实现Android图片拼接并保存至相册
android·java·前端
LucianaiB6 小时前
如何做好一份优秀的技术文档:专业指南与最佳实践
android·java·数据库
duwei_wang10 小时前
[Android]-Admob配置过多导致的慢消息
android
雨白12 小时前
发送自定义广播
android
方文_12 小时前
flutter~loading效果
flutter
雨白12 小时前
深入理解广播机制 (BroadcastReceiver)
android
唯有选择12 小时前
让你的应用界面好看的基石:Flutter主题Theme使用和扩展自定义字段
前端·flutter
婵鸣空啼16 小时前
GD图像处理与SESSiON
android
sunly_17 小时前
Flutter:导航固定背景图,滚动时导航颜色渐变
android·javascript·flutter
用户20187928316718 小时前
简单了解android.permission.MEDIA_CONTENT_CONTROL权限
android