当前位置:首页 > 手机资讯 > 正文

告别setState()! 优雅的UI与Model绑定 Flutter DataBus使用~给手机充电「告别setState()! 优雅的UI与Model绑定 Flutter DataBus使用~」

告别setState()! 优雅的UI与Model绑定 Flutter DataBus使用~给手机充电「告别setState()! 优雅的UI与Model绑定 Flutter DataBus使用~」

作者:Nayuta 链接:https://juejin.im/post/6868104488109604871 本文由作者授权发布。

Flutter开发中,大家都绕不开Widget的刷新,setState()是最简单的用法。但随着当app的交互变得复杂,setState出现的次数便会显著增加,每次setState都会重新调用build方法,这势必对于性能以及代码的可阅读性带来一定的影响。如何优雅的解决这个问题,不得不提到StreamBuilder,StreamBuilder是Flutter中异步构建的核心组件。许多著名的开源框架例如Bloc皆是基于此实现。如果StreamBuilder有了解可以直接看第二部分

一、局部刷新的关键点 StreamBuilder

现在页面上有两个数字key1和key2需要展示,当点击上方的按钮时,我们对应修改key1或者key2的值。

img

采用setState()的方式,我们知道很简单,建立本地变量key1,key2,然后放入对应的Text中直接展示。当我们点击按钮时使本地变量key1,key2做增加操作,之后调用setState()。

img

img

img

img

但当我刷新Key1的时候, 会同时重构Key2展示的两个Text,即使我的key2没有发生变化,显然这不是一种合理的做法。

其实Flutter中还提供了一个强大组件SteamBuilder来协助我们处理控件的刷新构建。

如图,是StreamBuilder使用基本结构,StreamBuidler基于dart中的异步核心之一Stream,采取观察者模式,发送方通过StreamControll发送数据,观察对象接收到数据后构建自己的内容。

从代码可知StreamBuilder接受两个参数,一个stream,表示我们监听的Stream(一个StreamBuilder监听一个Stream,但是一个Stream能被多个Widget监听),builder中传入我们需要构建的contentWidget。

这样Widget的构建完全由Stream触发,控件无需自行setState,它的构建完全由数据驱动,是一种响应式编程。也是许多开源框架例如Bloc等核心原理。

回到上面的例子中,当我们采用StreamBuilder后,上面的例子就变得非常的清晰了,我们建立两条StreamControler,然后把图中的展示key1和key2的两组Text分别由两个StreamBuilder包裹。

在key1的点击事件中往Stream中add数据,这样在key1的流上产生了一条数据,对应的监听者收到数据后,只更新自己的内容,不会重建其他区域。

二、DataLine如何优化StreamBuilder的麻烦使用

经过上面的了解,我们知道。StreamBuilder可以完美解决局部刷新的问题,但StreamBuilder也有着同样明显的缺点,使用起来非常麻烦,需要自己手动创建流,将控件用StreamBuilder包裹构造。

当我们的页面需要多个局部刷新的时候,Stream的编写将会非常麻烦。类似Provide的解决方案也需要设定顶级Widget,然后用consumer包裹子控件,调用更新等等操作。

有没有什么方式可以简化我们的使用呢?

我们注意到,StreamBuilder需要监听一个stream,而这个stream往往来自StreamControler。对于每个StreamControler来说,就像生活中的一条 一对多的数据线数据线(DataLine)一样。

对于这条DataLine,最核心的有两个方法

1、添加观察者(通过StreamBuilder包裹实际展示的contentWidget) : 类似数据线连接手机

2、发送数据 :类似通过数据线给手机充电(因为是一对多的过程)

基于这种思路,设计了一个SingleDataLine,对于这条“数据线"而言,其中T约束了这条线的使用数据类型,currentData能帮助我们拿到当前最新的数据,setData(T t)发送数据。

核心在于我们的addObserver中,该方法需要传入一个 返回值为Widget Function(BuildContext context, T data) observer的方法,这个传入的方是我们需要构建的Widget的构造方法。

这个addObserver方法返回一个DataObserverWidget控件,这个组件就是帮我们对StreamBuilder进行了封装,以此简化StreamBuilder的使用。

三、DataBus如何解决多个Stream的绑定

上面我们通过SingDataLine简化了StreamBuilder的使用,但当页面中有多个SingleDataLine的时候,对它的创建和管理,可能会成为一件麻烦的事儿。基于此设计了一个dataBus总线管理。

我们将每一个key和对应的DataLine存入Map中进行管理,通过直接调用getLine(key)的方法获取创建DataLine。而且由于MultDataLine是mixin定义,所以我们可以在任意的类中混入使用方法。例如直接在Widget中混入改类,调用getLine方法获取到StreamBuilder。

有话要说...

最新文章