我们封装了哪些好用的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,希望能够给读者带来一些思考。实际上个人认为封装的中心思想都是一致,仅是利用不同语言的特性。

相关推荐
louisgeek1 小时前
Flutter 动画之 Explicit 显式动画
flutter
早起的年轻人2 小时前
Flutter BigInt 是用于处理任意精度整数的特殊数字类型,专为解决超大整数运算需求而设计
flutter
leluckys2 小时前
flutter 专题 六十六 Flutter Dio包网络请求抓包解决方案
flutter
爱吃鱼的锅包肉2 小时前
Flutter路由模块化管理方案
前端·javascript·flutter
郁大锤2 小时前
Android Studio 国内镜像使用与 SDK 下载速度优化指南
android·ide·android studio
那就摆吧3 小时前
数据结构-栈
android·java·c语言·数据结构
奔跑吧 android3 小时前
【android bluetooth 框架分析 02】【Module详解 4】【Btaa 模块介绍】
android·bluetooth·bt·aosp13·btaa
tangweiguo030519873 小时前
Android Compose Activity 页面跳转动画详解
android·compose
Yang-Never4 小时前
ADB -> pull指令拉取手机文件到电脑上
android·adb·android studio
Yang-Never4 小时前
ADB -> pull指令推送电脑文件到手机上
android·adb·android studio