局部刷新
在Flutter中页面状态管理是非常重要的,更新页面状态也是我们在做项目时最频繁的操作,那么在Flutter中刷新页面状态直接调用setState方法是非常方便的,但是这样会直接更新build方法,刷新整个页面,但是在某些特定情况下,我们只想更新页面中的某一个widget并不需要刷新整个页面,这个时候就需要用到局部刷新的功能。
- StreamBuilder 基于Stream
官方说明:
[StreamBuilder], which is specialized for the case where only the most recent interaction
is needed for widget building.
专门构建于小部件数据更新时交互时使用的情况。
示例用法:
class TestPage extends StatefulWidget {
const TestPage({Key? key}) : super(key: key);
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> with TickerProviderStateMixin {
late StreamController _controller; // 控制器
int num = 0;
@override
void initState() {
super.initState();
_controller = StreamController.broadcast(); // 初始化
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("局部刷新"),
),
body: Center(
child: StreamBuilder(
initialData: num, // 初始化需要刷新的数据
stream: _controller.stream, // 控制器对应的stream
builder: (context, n) {
return Text("data=${n.data}");// n.data 对应initialData的数据类型
})),
floatingActionButton: FloatingActionButton(
onPressed: () {
_controller.sink.add(num++); // 更新数据
},
child: Icon(Icons.add),
),
);
}
@override
void dispose() {
super.dispose();
// 记得销毁
_controller.close();
}
}
在我们所需要更新的组件外套上StreamBuilder就可以了,用法也很简单,但是这样的用法如果在每个页面都写一遍的话也是比较繁琐的,所以我们需要将这个功能进行封装下。
封装工具类:
import 'dart:async';
import 'package:flutter/material.dart';
import 'stream_build_util.dart';
/// 局部刷新状态
class StreamBuild<T> {
late StreamController<T> _controller;
T? t;
final String key;
StreamBuild(this.key) {
_controller = StreamController.broadcast();
}
factory StreamBuild.instance(String key) {
return StreamBuild<T>(key);
}
get outer => _controller.stream;
get data => t;
// 改变数据发送
changeData(T t) {
this.t = t;
_controller.sink.add(t);
}
dis() {
_controller.close();
}
// 监听者
Widget addObserver(Widget Function(T t) ob, {required T initialData}) {
this.t = data ?? initialData;
// var streamBuild = this as StreamBuild<T>;
return StreamBuilderWidget<T>(
streamBuild: this,
builder: ob,
initialData: initialData,
);
}
}
class StreamBuilderWidget<T> extends StatefulWidget {
final StreamBuild<T> streamBuild;
final Widget Function(T t) builder;
final T? initialData;
const StreamBuilderWidget(
{Key? key,
required this.streamBuild,
required this.builder,
required this.initialData})
: super(key: key);
@override
_StreamBuilderWidgetState createState() => _StreamBuilderWidgetState<T>();
}
class _StreamBuilderWidgetState<T> extends State<StreamBuilderWidget> {
@override
Widget build(BuildContext context) {
return StreamBuilder<T>(
initialData: widget.initialData,
stream: widget.streamBuild.outer,
builder: (context, n) {
return widget.builder(n.data as T);
});
}
@override
void dispose() {
super.dispose();
widget.streamBuild.dis();
StreamBuildUtil.instance.onDisposeKey(widget.streamBuild.key); // 清除map数据
}
}
封装工具类:
import 'dart:collection';
import 'stream_build.dart';
/// 局部刷新工具类
class StreamBuildUtil {
static StreamBuildUtil? _instance;
StreamBuildUtil._();
factory StreamBuildUtil() {
return instance;
}
static StreamBuildUtil get instance => _getInstance();
static StreamBuildUtil _getInstance() {
if (_instance == null) {
_instance = StreamBuildUtil._();
}
return _instance ?? StreamBuildUtil._();
}
final HashMap<String, StreamBuild> dataBus = HashMap();
/// key = 刷新局部标记
StreamBuild getStream(String key) {
if (!dataBus.containsKey(key)) {
StreamBuild streamBuild = StreamBuild.instance(key);
dataBus[key] = streamBuild;
}
if (dataBus[key] == null) {
return StreamBuild.instance(key);
} else {
return dataBus[key]!;
}
}
void onDisposeAll() {
if (dataBus.length > 0) {
dataBus.values.forEach((f) => f.dis());
dataBus.clear();
}
}
void onDisposeKey(String? key) {
if (dataBus.length > 0) {
dataBus.remove(key);
}
}
}
在回到我们最初的例子,用法就变成了这样:
class TestPage extends StatefulWidget {
const TestPage({Key? key}) : super(key: key);
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> with TickerProviderStateMixin {
int num = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("局部刷新"),
),
body: Center(
child:
StreamBuildUtil.instance.getStream("streamKey").addObserver((t) {
return Text("data=${t.data}");
}, initialData: 0)),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 更新数据
StreamBuildUtil.instance.getStream("streamKey").changeData(num++);
},
child: Icon(Icons.add),
),
);
}
}
可以看到,我们就只需要关注我们的业务代码就可以了。 ---End