1、什么是状态
1.1、应用的状态就是当这个应用运行时存在于内存中的所有内容。包括了应用中用到的资源,所有 Flutter 框架中有关用户界面、动画状态、纹理、字体以及其他等等的变量。纹理,字体等系统已经处理好了,我们能改变的状态,比如更改需要重建页面时所需要的数据。比如用户在设置界面中点击了一个开关选项,改变了状态,这将会触发用户界面的重绘。
如何改变state,通知UI更新?
2、状态共享
状态共享为了解决子widget如果感知数据变化,以及父widget怎么将数据传递给子widget。
2.1、setState 通知framework当前的对象内部状态改变,然后会重新build当前的对象。
setState(() {
_myState = newValue;
});
void setState(VoidCallback fn) {
_element!.markNeedsBuild();
}
2.2、provider 提供数据给子类。
以项目中的provider的使用为例,项目中使用ChangeNotifierProvider,使用如下
Expanded(
child: ChangeNotifierProvider.value(
value: person,
child: Container(
child: Consumer<Person>(
builder: (context, person, child) {
int number = Random().nextInt(1000);
return Container(
height: 45,
color: Colors.deepPurple,
alignment: Alignment.center,
child: InkWell(
child: Text(
"change $number age = ${person.age}",
style: TextStyle(color: Colors.white),
),
onTap: () {
provider_person.getNetWorkData();
},
),
);
},
),
),
),
),
class Person extends ChangeNotifier {
String name = "";
int age = 10;
Person({required this.name, required this.age});
void getNetWorkData() async {
await Future.delayed(const Duration(milliseconds: 500), () {
this.age = Random().nextInt(2000);
notifyListeners();
});
}
void getNetWorkDataContext(BuildContext context) async {
print("load data");
await Future.delayed(const Duration(microseconds: 500), () {
Provider.of<Person>(context, listen: false).age = Random().nextInt(100);
notifyListeners();
});
}
Future<Person> getNetWorkDataFuture() async {
return await Future.delayed(const Duration(milliseconds: 500), () {
this.age = Random().nextInt(2000);
return this;
});
}
}
看下changeNotifyProvider的构造函数
第一种: 使用create方法创建一个ChangeNotifier,当ChangeNotifierProvider从树上移除的时候自动销毁。
create : 创建一个ChangeNotifier的对象,create函数只会执行一次。
lazy: 是否用到的时候再create,懒加载。
builder : 用于创建子widget,context可用于获得provider。
child: 更好的复用,减少child部分重绘,性能更好。
builder和child必须存在一个。
ChangeNotifierProvider({
Key? key,
required Create<T> create,
bool? lazy,
TransitionBuilder? builder,
Widget? child,
})
create中不可以是一个已经存在的value值,因为create只会执行一次,之后value值改变会没有效果。
2、提供已经存在的ChangeNotify
ChangeNotifierProvider.value({
Key? key,
required T value,
TransitionBuilder? builder,
Widget? child,
})
value : 已经存在的ChangeNotify对象,会创建或更改多次。
这个构造函数不可以在value参数处创建ChangeNotify,创建ChangeNotify会导致先前的value对象状态丢失。
3、provider原理
3.1 认识InheritedWidget
用于高效的向子widget传递数据的基础类,当数据改变时,rebuild会更新子widget数据。InheritedWidget和StateLessWidget有什么不同了?
abstract class StatelessWidget extends Widget {
@override
StatelessElement createElement() => StatelessElement(this);
}
abstract class InheritedWidget extends ProxyWidget {
@override
InheritedElement createElement() => InheritedElement(this);
}
class StatelessElement extends ComponentElement {
@override
void update(StatelessWidget newWidget) {
super.update(newWidget);
assert(widget == newWidget);
_dirty = true;
rebuild();
}
}
abstract class ProxyElement extends ComponentElement {
@override
void update(ProxyWidget newWidget) {
final ProxyWidget oldWidget = widget as ProxyWidget;
assert(widget != null);
assert(widget != newWidget);
super.update(newWidget);
assert(widget == newWidget);
updated(oldWidget);
_dirty = true;
rebuild();
}
}
InheritedElement继承自ProxyElement,可以看见StatelessElement如果widget需要更新,则直接rebuild,而InheritedWidget如果需要更新,则先调用updated(oldWidget),这个方法更新依赖的widget,然后再rebuild自己。
3.2、用该类实现一个类似Provider功能。
class State_Manager extends InheritedWidget {
Person? person;
Widget myChild;
State_Manager({required this.myChild, required this.person})
: super(child: myChild);
@override
bool updateShouldNotify(covariant State_Manager oldWidget) {
print("update-------");
if (person?.age != oldWidget.person?.age) {
return true;
}
return false;
}
static State_Manager? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<State_Manager>();
}
@override
InheritedElement createElement() {
ProviderElement element = ProviderElement(myWidget: this);
person?.addListener((age) => {element.markNeedsBuild()});
return element;
}
}
class ProviderElement extends InheritedElement {
InheritedWidget myWidget;
bool isNeedUpdate = false;
ProviderElement({required this.myWidget}) : super(myWidget);
@override
void markNeedsBuild() {
print("markbuild");
super.markNeedsBuild();
}
@override
State_Manager get widget => super.widget as State_Manager;
@override
Widget build() {
print("build element");
notifyClients(widget);
return super.build();
}
}
class Person {
String? name;
int? age;
void Function(int age)? listener;
set setAge(int age) {
this.age = age;
listener?.call(age);
}
void addListener(Function(int age)? listener) {
this.listener = listener;
}
Person({required this.age, required this.name});
}
使用
class _Apply_State extends State<State_Manager_Apply> {
late Person _person;
GlobalKey globalKey = GlobalKey();
@override
void initState() {
super.initState();
_person = Person(age: 23, name: "lisi");
}
@override
Widget build(BuildContext context) {
print("state_manager_build");
return Scaffold(
appBar: AppBar(
title: Text("状态管理"),
),
body: State_Manager(
myChild: Column(
children: <Widget>[Text_A(), Text_B(), Text_C(), Text_D() ],
),
person: _person,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_person.age = Random().nextInt(100);
setState((){
});
},
child: Text("改变child数据"),
),
);
}
}
class Text_C extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("text c build");
return SizedBox(
height: 100,
width: double.infinity,
child: Container(
padding: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
color: Colors.yellow,
child: InkWell(
onTap: () {
Person? person = State_Manager.of(context)?.person;
person?.setAge = Random().nextInt(300);
},
child: Text("C 我不需要改变",
style: TextStyle(color: Colors.black87, fontSize: 18)),
),
),
);
}
}
上述代码中, A B C D四个widget,当点击C更改数据后,由于A,B,C调用了
State_Manager.of(context)会向将该element加入到_dependencies中,看下加入代码。
@override
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
if (ancestor != null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
InheritedWidget dependOnInheritedElement(InheritedElement ancestor, { Object? aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies!.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget as InheritedWidget;
}
上述的State_Manager.of()就相当于观察者模式中的注册。之后rebuild(比如调用setState)会使dependencies集合中的widget更新。
@override
void update(ProxyWidget newWidget) {
final ProxyWidget oldWidget = widget as ProxyWidget;
super.update(newWidget);
assert(widget == newWidget);
updated(oldWidget);
_dirty = true;
rebuild();
}
@protected
void updated(covariant ProxyWidget oldWidget) {
notifyClients(oldWidget);
}
void notifyClients(InheritedWidget oldWidget) {
assert(_debugCheckOwnerBuildTargetExists('notifyClients'));
for (final Element dependent in _dependents.keys) {
// check that it really depends on us
notifyDependent(oldWidget, dependent);
}
}
void didChangeDependencies() {
assert(_lifecycleState == _ElementLifecycle.active); // otherwise markNeedsBuild is a no-op
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
上述updated(oldWidget)就会更新依赖的widget。可以注意到上述我们监听数据变化设置element.markNeedsBuild()和setState()方法中设置_element!.markNeedsBuild()不是同一个element。使用了setState会导致
State_Manager这个widget重建。而直接使用数据监听,不会使State_Manager重建,里面的child更新也是局部更新。
如图,点击C,则A,B,C会创建,D不会创建。如果直接点击floatButton,调用setState则abcd都会重新创建。
4、 provider框架
可以看到provider框架也是使用InheritedWidget实现的,以ChangeNotifyProvider为例,分析调用过程。
4.1、注册监听
//注册时机 InheritedProvider
@override
T get value {
element!._isNotifyDependentsEnabled = false;
_removeListener ??= delegate.startListening?.call(element!, delegate.value);
element!._isNotifyDependentsEnabled = true;
assert(delegate.startListening == null || _removeListener != null);
return delegate.value;
}
static VoidCallback _startListening(
InheritedContext e,
Listenable? value,
) {
value?.addListener(e.markNeedsNotifyDependents);
return () => value?.removeListener(e.markNeedsNotifyDependents);
}
void addListener(VoidCallback listener) {
if (_count == _listeners.length) {
if (_count == 0) {
_listeners = List<VoidCallback?>.filled(1, null);
} else {
final List<VoidCallback?> newListeners =
List<VoidCallback?>.filled(_listeners.length * 2, null);
for (int i = 0; i < _count; i++) {
newListeners[i] = _listeners[I];
}
_listeners = newListeners;
}
}
_listeners[_count++] = listener;
}
4.2、数据改变,通知刷新
void notifyListeners() {
for (int i = 0; i < end; i++) {
try {
_listeners[i]?.call();
}
}
}
上述的get value 就是Provider.of()调用,也就是每次获取值就注册了监听,监听的实现就是e.markNeedsNotifyDependents, notifyListeners就是去通知刷新element。
4.3、接收到监听,处理。
class class _InheritedProviderScopeElement {
@override
void markNeedsNotifyDependents() {
if (!_isNotifyDependentsEnabled) {
return;
}
markNeedsBuild();
_shouldNotifyDependents = true;
}
@override
Widget build() {
if (widget.owner._lazy == false) {
value; // this will force the value to be computed.
}
_delegateState.build(
isBuildFromExternalSources: _isBuildFromExternalSources,
);
_isBuildFromExternalSources = false;
if (_shouldNotifyDependents) {
_shouldNotifyDependents = false;
notifyClients(widget);
}
return super.build();
}
}
更新当前的element,调用build,然后调用notifyClients(widget),更新依赖的子widget。
4.4. FutureProvider和StreamProvider
//_DeferredDelegateState
@override
R get value {
element!._isNotifyDependentsEnabled = false;
_removeListener ??= delegate.startListening(
element!,
setState,
controller,
_value,
);
element!._isNotifyDependentsEnabled = true;
return _value as R;
}
//async_provider
DeferredStartListening<Future<T>?, T> _futureStartListening<T>({
required T initialData,
ErrorBuilder<T>? catchError,
}) {
return (e, setState, controller, __) {
if (!e.hasValue) {
setState(initialData);
}
var canceled = false;
controller?.then(
(value) {
if (canceled) {
return;
}
setState(value);
},
}
//_DeferredDelegateState
void setState(R value) {
if (_hasValue) {
final shouldNotify = delegate.updateShouldNotify != null
? delegate.updateShouldNotify!(_value as R, value)
: _value != value;
if (shouldNotify) {
element!.markNeedsNotifyDependents();
}
}
_hasValue = true;
_value = value;
}
当future和stream异步处理完成之后,通过setState函数回调,然后调用
markNeedsNotifyDependents,之后更新子widget流程就相同了。
5、子Widget获取值。
T read<T>() {
return Provider.of<T>(this, listen: false);
}
T watch<T>() {
return Provider.of<T>(this);
}
Selector<Counter, List<int>>(builder: (context, value, child) {
return Container(
alignment: Alignment.center,
child: Text(
"selector用于过滤一些不想要的改变\n ${value.toString()}",
textAlign: TextAlign.center,
),
);
}, selector: (context, otherValue) {
print("---${otherValue.count}");
List<int> list = [];
if (otherValue.count % 3 == 0) {
list.add(otherValue.count);
print("添加了 ${otherValue.count}");
}
return list;
});
Consumer<Person>(
builder: (context, person, child) {
print("conumser build");
int number = Random().nextInt(1000);
return Container(
height: 45,
color: Colors.deepPurple,
alignment: Alignment.center,
child: Text(
"change $number age = ${person.age}",
style: TextStyle(color: Colors.white),
),
);
},
),
read方法不可以在 [StatelessWidget.build]/[State.build]中调用,可以在点击事件中调用。
watch方法仅仅可以在[StatelessWidget.build] 和[State.build]调用。
consumer:为provider提供context,再者提供更好性能,复用child。
Selector : 等同于Cosumer,可以过滤一些值,防止value没有变化而rebuild。