本文我们来分析一下Provider中的Selector实现。Selector是我们Provider提供给我们实现条件刷新的组件,同样上个Demo演示。还是一样的Counter状态类。
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
ChangeNotifierProvider(
create: (context) => Counter(),
builder: (context, child) {
return Selector<Counter, int>(
selector: (context, counter) => counter.count,
builder: (_, data, __) {
return Text('$data');
},
);
},
)
Selector类里有Selector、Selector2、Selector3…,这是相对于需要Select多少个状态类数量。这里我们只需要选择Counter一个状态类里面的数据,所以我们只使用Selector即可。Selector、Selector2等都是继承自Selector0这个widget。
class Selector<A, S> extends Selector0<S> {
/// {@macro provider.selector}
Selector({
Key? key,
required ValueWidgetBuilder<S> builder,
required S Function(BuildContext, A) selector,
ShouldRebuild<S>? shouldRebuild,
Widget? child,
}) : super(
key: key,
shouldRebuild: shouldRebuild,
builder: builder,
selector: (context) => selector(context, Provider.of(context)),
child: child,
);
}
在父类Selector0的_Selector0State中buildWithChild,widget.selector(context)使用了子类传过来的selector调用了Provider.of(context),创建监听。那他是怎么做到指定条件刷新呢。在_Selector0State中会创建缓存旧Widget-cache、旧数据value,然后会判断widget是否相同、shouldRebuild条件、DeepCollectionEquality对比来判断是否需要更新组件。就这样实现了条件刷新widget。
class _Selector0State<T> extends SingleChildState<Selector0<T>> {
T? value;
Widget? cache;
Widget? oldWidget;
@override
Widget buildWithChild(BuildContext context, Widget? child) {
final selected = widget.selector(context);
final shouldInvalidateCache = oldWidget != widget ||
(widget._shouldRebuild != null &&
widget._shouldRebuild!(value as T, selected)) ||
(widget._shouldRebuild == null &&
!const DeepCollectionEquality().equals(value, selected));
if (shouldInvalidateCache) {
value = selected;
oldWidget = widget;
cache = widget.builder(
context,
selected,
child,
);
}
return cache!;
}
...
}