一篇文章,告别Flutter状态管理争论,问题和解决

Flutter 新一代状态管理框架 signals ,它究竟具备什么魔法和优势 开始解析在聊 signals.dart 之前,需要快速介绍 signals 的前置概念,附带还有 Preact、Preact Signals 、SolidJS 等关键词。首先需要说明一点,「Signals」 是业内通用的一种状态管理模式,而 signals.dart 项目就是 Preact Signals 的一个 Dart 移植版本,所以在最底层源码里你可以看到 Preact Signals 的核心原语,自然也就是包含了Signal 的细粒度、惰性求值和自动依赖追踪等能力。 阅读详情

起因

每隔一段时间,都会出现一个新的状态管理框架,最近在YouTube上也发现了有人在推signals, 一个起源于React的状态管理框架,人们总是乐此不疲的发明各种好用或者为了解决特定问题而产生的方案,比如Bloc, 工具会推陈出新,新的语法会带来更便捷的方式,但原理和优缺点是更重要的一面,我们接下来聊聊这一点。

原理

状态管理的起点是值的改变也就是通常代码中的set方法, 状态的终点在Flutter或者其他UI框架中,对单个绘制节点进行setDirty来标记一个需要重新绘制节点,最后生成新的持续帧来承接新的数据,在Flutter中通过setState 来实现。当我们明确了状态管理的起点和终点, 中间对于值的操作和缓存,diff算法,状态传递,状态转移过程等是这些状态管理框架们根据要解决的实际问题来做的权衡(trade off)。

  • figure 1 状态管理的空间

state_manage_space.png

需要权衡什么?

易用性

在Flutter开发中,有一句著名的话你可以不了解Flutter,但不能不知Getx, 这点很像Java服务端的spring框架, 提供了一套完备的开发工具,也许不是最合适于特定项目,但一定合适于简单项目。那Getx的权衡是什么? 笔者觉得托管,完备、简单,是Getx的最大权衡,比如,你需要全局使用Getx的组件,来包裹所有的Widget,这样Getx就可以托管你的程序,依赖注入,主题,屏幕尺寸,路由都可以被Getx管理。比如简单的Obx函数将StatefulWidget封装,通过全局的NotifyManager来注册,管理被捕获的值。

总的来说,Getx通过巧妙的架构设计,侵入式的托管式框架,确实做到了在简单项目中的面向Getx开发。

所以我们知道在状态管理时,第一个权衡,简单,好上手。

与Getx简单相反的是Bloc的复杂, Bloc 提供了全面且复杂的状态管理模式,Predictable可预测的以及Bloc的设计模式的结合使框架有很多的模版,是的更细致的状态更新管理,隔离的状态称为可能, 后面会结合Riverpod来解释这一优势。

状态传递

第一个需要权衡的点是状态转移,如果使用原生StatefulWidget,当我们Widget数开始庞大起来,不可避免的要进行组件的拆分降低维护难度,或者出于重用的目的,这样的操作势必会进行状态的转移,在这个维度就是百花齐放了,Getx和Rivierpod是将依赖管理和状态相结合,通过全局的状态声明和状态获取来达到这个目的,例如

/// 声明并加入到全局Scope

class DayChecked extends _$DayChecked {
  
  DateTime build() {
    return DateTime.now();
  }
}
/// 任意地方使用
final focusedDay = ref.watch(dayCheckedProvider); // 读取
ref.read(dayCheckedProvider.notifier).set(focusedDay) // 修改

// Getx用法
class ScheduleState {
  Rx<DateTime> focusedDay = DateTime.now().obs;
}
class ScheduleLogic extends GetxController {
  final ScheduleState state = ScheduleState();
}
// 使用
Get.find<ScheduleLogic>().state.focusedDay

全局的状态管理易用程度是中等的,Getx和flutter_hooks 都提供了局部的状态声明,这在Widget内部状态处理时更方便的,hook的概念起源于React,状态管理相对于Getx是一种更轻量的解决方案,稍后我们提及其他方面的优势。我们可以认为Hook更适合内部状态变化。

全局的状态管理带来一个较为严重的问题,虽然可以通过组合别的方式来解决,但确实不够完备。

例如:TodoList中,任务的子父级关系的,虽然是同一个页面,使用同一个状态管理类,但状态应该是独自的,全局的状态管理解决这个问题的方法是通过入参,这种形式,例如Getx中Get.find(tag)和riverpod的build(params)来生成多个状态管理.

  // 使用参数化区分不同状态
  logic = Get.find<TaskDetailLogic>(tag: task.id);
  ref.watch(taskDetailProvider(task.id));

这样会带来一个比较棘手的问题,我们必须将logic或者参数tag一级一级的传递,或者通过callback一级一级的回传操作,来保证状态的正确读取和修改,这点在复杂项目当中是很棘手的,当锚定的入参过多时,我们会考虑父子Widget传递logic和state,保证状态的正确引用,但这丧失了灵活性和Widget重用的范围。

这种情况下,在全局状态和Widget内部状态中间,需要一种状态管理, 局部状态管理的概念就能够很好的解决这个问题,Bloc是这种方式的代表,通过BlocProvider提供一个局部, 被挂载到局部的状态,可以被context.read<SignInBloc>()获取相关联的状态。riverpod也能做到局部状态,只是他的设计初衷并不是如此,所以使用局部状态时,会显得很蹩脚,分离context,使用ref, 也导致官方并不推荐使用局部状态的方式,这将会造成混乱。

figure 2 状态范围(Scope)

scope.png

状态操作

使用Riverpod的同学会特别喜欢Flutter Hook, 因为riverpod对状态的声明和操作是分离的,尽管代码上他们封装在一起,但我们知道,这是OOP的写法, 便于理解,因为在一些语言中,方法和状态是分离的,对象中内聚函数,第一个参数是Self, 同样,生成式的Riverpod通过另一种方式实现了分离。如下


abstract class NotifierBase<State> {
  NotifierProviderElement<NotifierBase<State>, State> get _element;

  
  
  State get state {
    _element.flush();
    return _element.requireState;
  }

  
  
  set state(State value) {
    // ignore: invalid_use_of_protected_member
    _element.setState(value);
  }

  
  Ref<State> get ref;

我们暂时关心如何通过设计达到这个目的,我们需要关心的是状态的操作是内部的,也就是被限制的,在ReactHook中,类似于[set, get], 返回的值并没有直接修改的能力,相较于Getx的 1.obs和 flutter hook的useState(1),是一个更加内聚的设计,但丧失了灵活性,两者需要在不同场景下结合使用。

状态的声明有两种,基于Stream或者Listenable,两者都是响应式中重要的组成部分,不同的状态管理框架会权衡选择或者组合使用,例如,riverpod是基于Listenable, Bloc基于Stream, Getx则是混合使用的,我们大部分情况下不需要考虑状态的声明, 状态的修改是更影响开发体验,例如我们使用riverpod必须使用模版方法改变内部的值,然后借用freezed生成不可变对象, 保证值被完整的更新。或者实现equal方法主动进行diff并通知值的变化。例如:bloc+freezed


class SignInState with _$SignInState {
  const factory SignInState({
    String? password,
    required Option<String> passwordError,
  }) = _SignInState;

  factory SignInState.initial() => SignInState(
        passwordError: none(),
      );
}
class SignInBloc extends Bloc<SignInEvent, SignInState> {
  SignInBloc() : super(SignInState.initial()) {
    on<SignInEvent>((event, emit) async {
      await event.map(
        passwordChanged: (PasswordChanged value) {
          emit(
            state.copyWith(
              password: value.password,
              emailError: none(),
            ),
          );
        },
      );
    });
  }
}

这种状态的修改对简单状态修改来说比较冗余,对层级复杂状态的修改,freezed就会很累赘,试想一下一个三级以上的嵌套, 例如:


class Task with _$Task {
  const factory Task({
    String? id,
    Alert? alert,
  }) = _Task;
}


class Alert with _$Alert {
  const factory Alert({
    String? id,
    Trigger? trigger,
  }) = _Alert;
}


class Trigger with _$Trigger {
  const factory Trigger({
    String? id,
    required DateTime time,
  }) = _Trigger;
}


class TaskDetail extends _$TaskDetail {
  
  Task build() {
    return Task();
  }
  /// 修改其中的一个值
  changeTrigger(DateTime dateTime) {
    state = state.copyWith(
        alert: state.alert?.copyWith(
            trigger: state.alert?.trigger?.copyWith(time: dateTime)));
  }
}

这是一个很常见的场景,在riverpod的官方文档中,我们可以看到将网络请求作为状态返回。这种在实际的复杂项目中是极其不推荐使用freezed或者说,引入不可变性, 这会导致灾难,虽然可以使用unfreezed放开部分权限,但这违背了freezed的设计初衷。多层级且要修改 的Http请求并不适合作为状态返回,我们的状态管理,需要针对是ViewModel, 这种情况下,一般解决方案会有两种。

  • 主动通知 ref.notifyListener
  • 将多层级数据结构展开(flat)

这取决于对数据操作的频率和数据字段的难度,需要在实际使用当中进行权衡,需要额外关注的是,如果我们需要记录状态的变化,则freezed的不可变性会是更好的解决方案,需要优先考虑。

第二个常见的场景是需要持久化存储的时候, 不可变性限制了很多,比如不能修改内部变量,不能添加方法(可以通过extension),不能够使用继承, 例如 Hive 的Object就不能被继承来实现更改,当然,因为不可变的特性,也无法修改。

总的来说,在Getx中,模版中的state概念类似ViewModel的载体,内部是单独的小的state, 我们可以直接监听小的state,这也是Getx很灵活的一点。其他的框架则更多偏向于state整体的管理和更新(bloc中cubit很像但需要太多模版代码),freezed的限制和使用可以参考我的另一篇文章,不再赘述,因为这种生成式或者将来添加的宏都会遇到类似的问题,所以多聊一点。

状态的结束

riverpod在官网提及自己的优势是,自动生命周期管理。这点确实是状态管理的一个难点,也是开发者经常会忽略的一个点,当我们使用StatefulWidget时我们并不需要考虑这个问题,因为state随着Widget结束而释放,但我们使用Stream或者Listenable时,如何释放,变成了一个棘手的问题,flutter hook通过包装的Element, LinkedList<_Entry<HookState<Object?, Hook<Object?>>>>? _needDispose;, 调用use时加入dispose列表。riverpod通过侵入Widget树,通过Element监听生命周期,并管理依赖。

  
  
  void dispose() {
    runOnDispose(); // 魔法
    for (final sub in _dependencies.entries) {
      sub.key._providerDependents.remove(this);
      sub.key._onRemoveListener();
    }
    _dependencies.clear();
    _externalDependents.clear();
  }

其中runOnDispose() 就是riverpod的魔法, 可以通过他来自动取消Http请求的UI相关的耗时作业。 对于状态结束的监听和操作每个框架的实现细节不一致,但本质上却是要回归到Element 的生命周期函数,以及针对Stream和Listenable两种方式的Dispose的处理。

状态依赖和传递

我们大部分时间,大部分需求都是在处理简单任务,例如,将数据库数据或服务接口整合,然后布局,填充样式,最终渲染到页面。简单任务通常是简单的流程,这也是为什么官方更推荐riverpod的原因,因为它更契合这种场景,我们不需要做业务层级的分离,只需要在某个地方声明某个网络请求provider,然后监听结果,或者修改结果。这是非常理想的情况,稍微复杂的情况,就需要状态之间的依赖和传递了,例如这个场景,

这个场景下,任务列表是依赖于选中日期的,不同的状态处理框架提供了不同的解决方法,虽然本质上都是对Stream和Listenable的监听,但对于状态的依赖管理和易用性是有很大差别的,Getx的方式会比较普通,扩展了Stream的函数,但仍需要主动Listen, riverpod的写法更巧妙,在语法上有很大的改善,比如当前这个场景。我们如果使用riverpod, 代码如下

(dependencies: [DayChecked, TaskList])
class DayTasks extends _$DayTasks {
  
  Future<List<TaskModel>> build() async {
    final checkedDay = ref.watch(dayCheckedProvider);
    // get task by checkDay
    retunr await serivce.get(checkedDay);
  }
}

区别于flutter_hook的函数是不明确的,例如实现相同功能,可能需要如下代码

    final checkedDate = useRef(DateTime.now());
    final taskList = useState(<TaskModel>[]);
    useEffect(() {
      taskList.value = service.get(checkedDate);
    }, [checkedDate.value]);

对于状态的传递,方程式的传递是相对优雅的,在数学上,我们知道y = 2x, 或者 z = 3x + 2y + 1 这样的简单等式, 能够优雅的以纯函数式来实现状态的转移是极其优雅的,对于这样的依赖传递形式的状态转移方程,riverpod的实现要优雅且严谨很多,更不容易出错。设想一个场景,用户是否为VIP, 这是一个简单状态,大多数情况下比用户信息更频繁的去读取,这个字段也需要被设计到用户信息接口,如果我们对UI层只提供简单的VIP状态,我们可以使用如下写法。

()
class UserConifg extends _$UserConifg {
  
  UserModel build() {
    return UserModel(avatar: '', id: "1", nickName: "nickName", pay: true);
  }
}

(dependencies: [UserConifg])
class Vip extends _$Vip {
  
  bool build() {
    final user = ref.watch(userConifgProvider);
    return user.pay;
  }
}

上述方式体现了这种方式的优雅,我们甚至可以将UserConifg放到别的包下,将Vip状态和UI关联,这种方式优雅的结构了复杂场景下的状态转移和高内聚,低耦合的原则。回到线性方程,它也符合y = 2x代数方程的思维。

总结:

任何领域都大概率都没有银弹, 软件开发领域也是如此,我们创造工具,使用工具,改进工具,才有软件的繁荣。不一定非要讨论那个框架或技术有高低差异。在实际开发中,稳定,熟悉是稳定三角的另外两个重要的方面,不同的框架的缺点,总会有一些或者优雅,或者败絮其中的解决方案,在项目中,最重要的适合,合适的工具会让我们开发过程事半功倍,其次是稳定性和学习难度, 不过,一切都需要合适的权衡(trade off)动态的去匹配当下最重要的事。

【Flutter】状态管理:高级状态管理 (Riverpod, BLoC) 当项目变得更加复杂时,简单的状态管理方式(如 `setState()` 或 `Provider`)可能不足以有效地处理应用中状态的变化和业务逻辑的管理。在这种情况下,高级状态管理框架,如 `Riverpod` 和 `BLoC`,可以提供更强大的工具,用于处理复杂的状态流、逻辑分离以及响应式编程。 阅读详情

相关推荐

Flutter GetX实战:5分钟搞定跨页面交互与状态管理

本文通过一个跨页面计数器的实战案例,详细介绍了Flutter GetX框架如何简化状态管理和跨页面交互。GetX通过依赖注入机制,让开发者无需依赖BuildContext即可轻松实现页面间Controller的直接调用与状态同步,从而大幅提升开发效率与代码可维护性。

weixin_28040125的博客 314

【亲测免费】 Signals.dart 使用教程

Signals.dart 使用教程 1. 项目介绍 Signals.dart 是一个基于 Preact Signals 的 Dart 库,旨在简化 Dart 和 Flutter 中的响应式编程。它提供了一个细粒度的响应式系统,能够自动跟踪依赖关系并在不再需要时释放它们。Signals.dart 支持 Dart JS(HTML)、Shelf Server、CLI(和 Native)、VM 以及 Fl...

gitblog_00397的博客 1190

uni-app开发者迁移Flutter指南:如何避免重写全部代码?

本文为uni-app开发者提供了向Flutter迁移的实战指南,重点阐述如何通过渐进式重构而非完全重写来降低迁移成本。文章详细介绍了迁移前的战略评估、核心概念与代码的映射转换、以及模块化迁移与混合开发等关键策略,旨在帮助开发者高效利用现有资产,平稳过渡到Flutter跨平台开发框架,并享受其性能优势。

z4a5b6的博客 488

Flutter 三方库 signals_core 的鸿蒙化实战 - 引入高性能细粒度响应式状态管理

本文介绍了将Flutter三方库signals_core应用于OpenHarmony开发的实践方案。signals_core是一种基于响应式原语的状态管理引擎,通过Signal信号机制实现精细化的依赖追踪,确保状态变更时仅更新最小UI单元,有效解决冗余渲染问题。文章详细解析了其核心原理、API使用方式,并展示了在鸿蒙平台上的适配方法。通过signals_core可实现高频率数据看板等场景的局部精准刷新,配合Watch组件能进一步优化性能,避免全局重绘,为OpenHarmony应用开发提供高性能状态管理解决方

2601_95372576的博客 611

Flutter框架GetX从入门到精通第三篇:响应式状态管理(Obx)

Flutter框架GetX从入门到精通第三篇:响应式状态管理(Obx)。本系列将带你从零开始,一步步掌握 GetX 框架的核心功能与实战技巧。

鹏多多的博客 192

Flutter框架GetX从入门到精通第一篇:初识GetX与环境搭建

Flutter框架GetX从入门到精通第一篇:初识GetX与环境搭建。本系列将带你从零开始,一步步掌握 GetX 框架的核心功能与实战技巧。

鹏多多的博客 276

Flutter 状态管理终极选型指南 2025:从 setState 到 Signals,找到最适合你的那一款

Flutter 状态管理终极选型指南 2025:从 setState 到 Signals,找到最适合你的那一款

2501_93814044的博客 1338

Rockchip rv1126平台在gstreamer1中添加OpenCv实现视频流负片的效果

rv1126 gstreamer opencv negetive effect

Aisy_D的专栏 1463

告别Flutter状态管理痛点:KVOControllerFlutter插件实现响应式数据监听

更多详细信息,请参考: - [FBKVOController.h](https://link.gitcode.com/i/bb68f1df5cdb0c0d202206a0997b6e69) - [FBKVOController.m](https://link.gitcode.com/i/463bcc01b2374d98691e2ba1aed8c2d9) - [NSObject+FBKVOContr...

gitblog_00835的博客 867

从硬件异常到代码救赎:RH850内存访问错误(MAE)的深层诊断与艺术

本文深入探讨瑞萨RH850微控制器的内存访问错误(MAE)诊断与解决方法。针对程序跑飞和Flash Driver交互中的潜在陷阱,提供系统性硬件异常分析框架和防御性编程实践,帮助嵌入式开发者从底层机制到代码层面有效预防和修复MAE问题,提升系统稳定性。

pytorch8learner的博客 195

抖音a_bogus参数逆向避坑指南:从环境检测到XHR请求的全流程解析

本文详细解析了抖音a_bogus参数在v1.0.1.19版本下的逆向工程全流程,重点介绍了如何通过PyV8Env框架进行有效的补环境操作,以绕过严格的环境检测。内容涵盖从环境初始化、关键事件触发到模拟XHR请求获取签名的完整步骤,并提供了可运行的Python代码示例和常见检测点的避坑指南,帮助开发者稳定生成有效的a_bogus参数。

tech5的博客 600

【Flutter for HarmonyOS】告别迟到!打造你的专属智能打卡器:状态管理与鸿蒙部署全攻略!

本文介绍了一个基于Flutter的打卡器应用开发方案。项目采用Flutter 3.x和Dart 2.x技术栈,核心功能包括考勤打卡和历史记录管理。文章详细讲解了数据模型设计(CheckinRecord类和CheckinStatus枚举)、状态管理机制(初始化加载、今日状态判断)以及打卡操作逻辑。应用界面通过动态文本和颜色反馈打卡状态,提供上班/下班打卡功能,并支持历史记录查看。技术实现上采用了自定义组件复用和多语言支持等优化措施,为用户提供简洁直观的打卡体验。

2501_94019622的博客 692

太速科技-基于DSP TMS320C6678+FPGA XC7V690T的6U VPX信号处理卡

当多块盘并行工作时,存储阵列读写带宽成指数增长,2块盘则≥4GB/s,4块盘则≥8GB/s,以此类推。存储阵列的存储容量由单盘配置决定,目前单块NVME存储盘存储容量可选择512GB、1TB、2TB、4TB、8TB、16TB。硬盘管理通过文件系统,FPGA的PCIeX4与 6U VPX主板互联,操作系统直接映射管理硬盘,也可以通过前面板QSFP+ 光纤导出给其他服务器设备。本方案优势就是集中的进行采集,存储,计算一体化,降低硬件成本、功耗,减小设备体积、重量。信号处理,无线电通信领域。

Orihard_的博客 678

告别状态混乱:Flutter Bloc响应式UI实战指南

你是否还在为Flutter应用中的状态管理而头疼?用户操作后界面不更新、多个组件状态同步困难、业务逻辑与UI纠缠不清?本文将带你一步掌握Flutter Bloc(Business Logic Component,业务逻辑组件)设计模式,通过实战案例构建真正响应式的用户界面。读完本文,你将能够: - 理解Bloc模式的核心原理与优势 - 掌握Flutter Bloc库的核心组件使用方法 - 构建一...

gitblog_00026的博客 918

RISC-V详细介绍

文章目录写在前面什么是RISC-VRISC-V诞生的背景ISA霸权摩尔定律的穷途末路穷困潦倒的学者不断增长的指令数量RISC-V架构设计思想如何设计一个好的ISARISC-V之RV32I四个典型特点RISC-V之乘除法指令指令格式用乘法代替常数除法RISC-V之RV64RISC-V的特权架构机器模式监管者模式 写在前面 本文主要基于RISC-V中文手册,其中包括但不限于一些网络的资料。本文版权属于skywf,转载或借用请联系作者。 什么是RISC-V RISC-V(发音为“risk-five”)是一个基于

skywf的博客 3万+

Vulkan入门系列3 - 绘制三角形代码解析(全)

【代码】Vulkan入门系列3 - 绘制三角形完整代码(带详细注释)

GPU全栈博主 1033

告别护眼烦恼:Flutter Go一键切换深色/浅色模式全指南

在移动应用开发中,主题切换功能已成为提升用户体验的关键特性。 Flutter Go作为包含140+组件的开发者工具APP,其主题系统不仅支持基础的颜色定制,还提供了灵活的深色/浅色模式切换方案。本文将从实现原理到实际操作,带你全面掌握Flutter Go中的主题切换机制。 ## 主题系统架构解析 Flutter Go采用双层主题架构设计,通过Material和Cupertino两套主题系统满足...

gitblog_00491的博客 811

Microsoft Forms功能深度解析:企业数据收集与协作的智能利器

Microsoft Forms是微软365生态中的在线表单工具,支持问卷调查、测验和投票创建,具备拖拽式界面、多题型设计和实时数据分析功能。其核心价值在于易用性、跨平台兼容性以及与Teams、SharePoint等微软服务的深度集成,满足GDPR/HIPAA等合规要求。提供表单创建、权限管理、自动化流程(通过Power Automate)和审计日志等功能,适用于金融、医疗、教育等多行业场景。虽然存在逻辑分支有限等约束,但通过案例证明能显著提升数据收集效率(达70-85%)。使用时需注意许可证配置(Busin

xueyunshengling的博客 9124

告别前端难题:Flet如何用Flutter技术简化Python应用开发

你是否曾因Python开发GUI应用需要学习复杂的前端技术而却步?是否梦想过用Python就能构建跨平台的精美应用?本文将揭示Flet如何借助Flutter技术,让Python开发者轻松实现这一目标,无需前端经验也能打造专业级应用。 ## Flet与Flutter的技术联姻 Flet是一个让Python开发者能够轻松构建实时Web、移动和桌面应用的框架。其核心优势在于将Flutter的强大UI...

gitblog_00332的博客 571

Modbus协议学习第一篇之基础概念

因工作需要而接触Modbus,正在恶补知识,利用博客的方式来加深理解和记忆,同时希望同行大佬能一起交流。

hzf978742221的博客 880

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Flutter艺术探索-设计模式在Flutter中的应用:单例、工厂、观察者

单例模式是管理全局资源的利器,Dart用factory和static就能优雅实现,但要注意它对可测试性的影响。工厂模式与Flutter动态构建UI的需求天作之合,它能让你干净利落地封装对象创建逻辑。观察者模式是Flutter响应式编程的核心,从setState到provider,都在用它同步数据和UI。最后想说的是,设计模式是为你服务的工具,而不是必须遵守的教条。千万别为了用模式而用模式。

nanxuan521的专栏 715

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

告别Context!用GetX实现Flutter弹窗/底部菜单的3种优雅方式

本文深入探讨了如何利用GetX框架解决Flutter开发中依赖Context的痛点,详细介绍了三种免Context实现弹窗、底部菜单和提示的优雅方式。通过Get.snackbar、Get.dialog和Get.bottomSheet,开发者可以在业务逻辑层直接触发UI交互,实现代码解耦,提升开发效率和可维护性。

weixin_29001419的博客 209

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Feature-first 分层架构:Flutter Boilerplate 目录设计的 5 大原则

如果你正在寻找一份可直接复用的 **Flutter Boilerplate**,或者纠结于"新项目目录到底该怎么组织",那么这篇文章正是为你准备的。所谓 **Feature-first 分层架构**,核心思想是让代码按"业务功能"而非"技术类型"来组织。本文将以一个基于 RiverPod、Dio、go_router、Freezed 并借助 very_good_cli 生成的真实开源项目为例,为你拆

gitblog_00094的博客 498

flutter学习笔记

1.跨平台移动UI框架2.与现有的代码一起工作(可以直接嵌入到原生代码中或直接把原生代码嵌入到自己的代码中运行)3. 完全免费、开源。

haoxuhong的博客 8243

必看,使用Provider优雅解决Riverpod的参数依赖

遇到问题,解决问题是技术人的一个思考准则,当我们遇到丑陋代码时,总可以找到合适的姿势去改变一点,使之优雅好用一点,世界上没有银弹, 但软件开发领域因为不断的进步,也在逐渐的越来越好(至少不想回去做Android原生)。可以把疑问放到评论区,一起讨论。

PirateBrook的天梯 1393

Flutter:一次编写,处处运行?不!是处处优雅运行!!!

下载SDK,创建你的第一个Flutter项目,感受一下“真香”定律!💪🏻 (等等,没图标,那就…的跨平台解决方案之一。Google的持续巨额投入、活跃的社区、不断完善的生态,都是强有力的背书。其“一次编写,处处运行”的愿景,在移动端已经实现得非常出色,在Web和桌面端也在快速追赶。那份“热重载”带来的开发快感,那份跨端一致的优雅,那份性能逼近原生的惊艳,会让你爱上它!Flutter的渲染引擎会高效地遍历、渲染这棵树。如果你是新手,想进入移动开发或者探索跨平台,如果你是老手,被多端开发和维护折磨,

pythonphoenix的博客 1068
上一篇: Flutter开源项目Appflowy学习
下一篇: Flutter中被屏蔽的概念,Scheduler(调度器)
PirateBrook
博客等级 码龄11年 90粉丝 40原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值