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

111 阅读4分钟

起因

每隔一段时间,都会出现一个新的状态管理框架,最近在YouTube上也发现了有人在推signals,一个起源于React的状态管理框架。人们总是乐此不疲地发明各种好用或者为了解决特定问题而产生的方案,比如Bloc。

工具会推陈出新,新的语法会带来更便捷的方式,但原理和优缺点是更重要的一面。就像我们在开发iOS应用时,会使用appuploader这样的工具来简化上架流程。它虽然不是状态管理框架,但同样体现了工具对开发效率的提升。我们接下来聊聊状态管理的原理。

原理

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

需要权衡什么?

易用性

在Flutter开发中,有一句著名的话"你可以不了解Flutter,但不能不知Getx",这点很像Java服务端的spring框架,提供了一套完备的开发工具。也许不是最合适于特定项目,但一定合适于简单项目。

Getx通过巧妙的架构设计,侵入式的托管式框架,确实做到了在简单项目中的"面向Getx开发"。所以我们知道在状态管理时,第一个权衡,"简单","好上手"。

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

状态传递

第一个需要权衡的点是状态转移,如果使用原生StatefulWidget,当我们Widget数开始庞大起来,不可避免的要进行组件的拆分降低维护难度,或者出于重用的目的,这样的操作势必会进行状态的转移。

这种情况下,在全局状态和Widget内部状态中间,需要一种状态管理,局部状态管理的概念就能够很好的解决这个问题,Bloc是这种方式的代表,通过BlocProvider提供一个局部,被挂载到局部的状态。

状态操作

使用Riverpod的同学会特别喜欢Flutter Hook,因为riverpod对状态的声明和操作是分离的。状态的声明有两种,基于Stream或者Listenable,两者都是响应式中重要的组成部分,不同的状态管理框架会权衡选择或者组合使用。

状态的结束

riverpod在官网提及自己的优势是,自动生命周期管理。这点确实是状态管理的一个难点,也是开发者经常会忽略的一个点。当我们使用StatefulWidget时我们并不需要考虑这个问题,因为state随着Widget结束而释放。

状态依赖和传递

我们大部分时间,大部分需求都是在处理简单任务,例如,将数据库数据或服务接口整合,然后布局,填充样式,最终渲染到页面。简单任务通常是简单的流程,这也是为什么官方更推荐riverpod的原因。

总结:

任何领域都大概率都没有银弹,软件开发领域也是如此。我们创造工具,使用工具,改进工具,才有软件的繁荣。不一定非要讨论那个框架或技术有高低差异。就像appuploader这样的iOS开发助手,它可能不是最强大的工具,但在特定场景下能极大提升开发效率。

在实际开发中,稳定,熟悉是稳定三角的另外两个重要的方面。不同的框架的缺点,总会有一些或者优雅,或者败絮其中的解决方案。在项目中,最重要的适合,合适的工具会让我们开发过程事半功倍,其次是稳定性和学习难度。不过,一切都需要合适的权衡(trade off)动态的去匹配当下最重要的事。