前语
最近闲下来在回顾常识点的时分,发现用了很久的Get.context却并不知道它的详细完成逻辑,和GlobalKey获取的BuildContext的方法又有什么共同点和差异点。今天就来剖析一下它们。
GlobalKey的完成
@optionalTypeArgs
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
factory GlobalKey({ String? debugLabel }) => LabeledGlobalKey<T>(debugLabel);
const GlobalKey.constructor() : super.empty();
Element? get _currentElement => WidgetsBinding.instance.buildOwner!._globalKeyRegistry[this];
BuildContext? get currentContext => _currentElement;
Widget? get currentWidget => _currentElement?.widget;
T? get currentState {
final Element? element = _currentElement;
if (element is StatefulElement) {
final StatefulElement statefulElement = element;
final State state = statefulElement.state;
if (state is T) {
return state;
}
}
return null;
}
}
GlobalKey是一个抽象类,咱们创立的GlobalKey实践回来的是LabeledGlobalKey,这儿咱们不去探究。
GlobalKey内部完成十分简单,供给了三个getter,这儿咱们要探究的是currentContext。
currentContext从何而来
Element? get _currentElement => WidgetsBinding.instance.buildOwner!._globalKeyRegistry[this];
BuildContext? get currentContext => _currentElement;
能够看到currentContext获取的是_currentElement,_currentElement又是从_globalKeyRegistry中获取的传入当时this目标。
class BuildOwner {
final Map<GlobalKey, Element> _globalKeyRegistry = <GlobalKey, Element>{};
void _registerGlobalKey(GlobalKey key, Element element) {
_globalKeyRegistry[key] = element;
}
void _unregisterGlobalKey(GlobalKey key, Element element) {
if (_globalKeyRegistry[key] == element) {
_globalKeyRegistry.remove(key);
}
}
}
能够看到在BuildOwner关于_globakKeyRegistry的完成也很简单,一个GlobalKey做key,Element做value的map,供给了增加与移除的办法。这两个办法又是何时调用的呢。
GlobalKey增加、撤销
咱们都知道Globalkey是作为key传入Widget的,咱们随意找一个Widget一探究竟。
abstract class StatefulWidget extends Widget {
const StatefulWidget({ super.key });
}
abstract class Widget extends DiagnosticableTree {
const Widget({ this.key });
final Key? key;
}
咱们在Widget传入的key终究会赋值给Widget,而Widget仅仅作为配置项终究创立的是Element,所以咱们进入Element检查。
abstract class Element extends DiagnosticableTree implements BuildContext {
void mount(Element? parent, Object? newSlot) {
if (parent != null) {
_owner = parent.owner;
}
final Key? key = widget.key;
if (key is GlobalKey) {
owner!._registerGlobalKey(key, this);
}
}
void unmount() {
final Key? key = _widget?.key;
if (key is GlobalKey) {
owner!._unregisterGlobalKey(key, this);
}
}
去掉无关代码,ELement中增加和移除GlobalKey的当地有两处,mount挂载和unmount撤销挂载,只有传入的key为GlobalKey时才会履行。
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
Element? get _currentElement => WidgetsBinding.instance.buildOwner!._globalKeyRegistry[this];
BuildContext? get currentContext => _currentElement;
}
再回过头来看GlobalKey内部完成,就能理解GlobakKey是怎样拿到当时当时BuildContext的了。
Get.context的完成
extension GetNavigation on GetInterface {
GlobalKey<NavigatorState> get key => _getxController.key;
BuildContext? get context => key.currentContext;
static GetMaterialController _getxController = GetMaterialController();
}
点击检查Get.context源码,咱们能够找到上面三行代码,能够看到Get获取context的方法也是用的GlobalKey,它仅仅对这个方法做了一层封装供咱们运用。
这儿的key是从GetMaterialController中获取的,接下来咱们来看看在GetMaterialController中key是怎样界说的。
Get中GlobalKey是怎样创立的
class GetMaterialController extends SuperController {
var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default');
GlobalKey<NavigatorState> get key => _key;
GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
_key = newKey;
return key;
}
}
在GetMaterialController中有一个默许的key,同时也能调用addKey替换默许的key,这个默许的key又是何时生效的呢。
GlobakKey怎样起作用
咱们把目光放回到main.dart中,再运用了Get咱们都会把MaterialApp替换成GetMaterialApp,而Get对MaterialApp对其做一层封装便是为了履行自己的一系列操作逻辑。
class GetMaterialApp extends StatelessWidget {
final GlobalKey<NavigatorState>? navigatorKey;
const GetMaterialApp({
Key? key,
this.navigatorKey,
});
@override
Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
builder: (_) =>
MaterialApp(
navigatorKey: (navigatorKey == null
? Get.key
: Get.addKey(navigatorKey!)),
)
}
能够看到,在Get中假如咱们传入了navigatorKey就调用addKey替换它的默许key,假如没有传入就运用Get的默许key。
看到这儿咱们也就能理解Get.context是怎样起作用和获取到了。
总结
-
GloblKey终究赋值给Widget、在对应的Element中调用BuildOwner进行增加和撤销 -
GlobalKey获取到的key是在BuildOwner中增加时传入的当时Element -
Get中有默许的GlobalKey,在GetMaterialApp中假如咱们传入了navigatorKey,就会代替默许的key -
Get.context原理便是GlobalKey,Get仅仅对这种方法的一种封装
关于BuildOwner的常识假如有不了解的,Flutter框架剖析 — runApp初始化里面有对WidgetBinding和BuildOwner有的介绍。
