前言 GetX 是 Flutter 上一个轻量且强大的状态管理框架,它不仅包含了状态管理 ,还有路由管理,主题管理,国际化多语言管理,网络请求,数据验证,Dialog,Snackbar 等功能,在一定程度上,减少了我们的开发时间,提高了工作效率。这么好用的一个框架,让我们来学习一下吧。
在我看来,GetX 最核心也是最具有特色的功能是它的状态管理功能,因此今天我们主要的任务就是把 GetX 的状态管理功能给整明白,后续我也会手把手带领大家去手撸 GetX 状态管理的核心源码实现。
问题 为了让大家更好的去理解和阅读源码,在此,我先抛出几个问题,大家可以去思考一下?
1、你了解 Dart 中的函数类型吗?怎么定义?
2、typedef 关键字的作用是什么?
3、extension 关键字的作用是什么?
4、如何定义一个泛型方法?Dart 中的泛型方法和 Java,Kotlin 有啥区别?
5、你了解 Dart 中的命名构造方法和 factory 构造方法吗?
6、你知道 Dart 中的 getter,setter 方法要怎么写吗?
7、Dart 中的 mixin 是怎么一回事?
如果你心里对于上面的这些问题有疑问🤔️,那么就跟着我的步伐继续往下走吧
一、前置知识 1.1、Dart 中的函数类型 函数类型的定义:将一个函数当作类型的类型就是函数类型,它可以:
1、作为一个函数的参数或返回值
2、赋值给一个变量
1.1.1、Kotlin 中的函数类型 对比 Kotlin 中的函数类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 (String,Int ) -> Unit () -> Unit fun numberPlus (num1: Int ,num2: Int ,func: (Int ,Int ) -> Int ) : Int { val sum = func(num1,num2) return sum }fun main () { val numberPlus = numberPlus(10 , 20 ){ num1,num2 -> num1 + num2 } val numberMinus = numberPlus(10 , 20 ){ num1,num2 -> num1 - num2 } println(numberPlus) println(numberMinus) }30 -10
1.1.2、Dart 函数类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void Function (String ,int )void Function () int numberPlus(int num1,int num2,int Function (int ,int ) sum){ return sum(num1,num2); }void main() { print (numberPlus(10 , 20 , (num1, num2) => num1 + num2)); print (numberPlus(10 , 20 , (num1, num2) => num1 - num2)); }30 -10
1.2、typedef 关键字 typedef 作用:给任意类型设置一个别名,通常情况下我们会给定义比较长的类型使用 typedef ,例如:函数类型
如下例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 typedef IntOperation = int Function (int ,int );void main() { IntOperation intOperation = (a,b) => a + b; print (intOperation(4 ,6 )); }10 typedef IntList = List <int >;void main() { IntList intList = [1 ,2 ,3 ]; print (intList); } [1 , 2 , 3 ]typedef StringDynamicMap = Map <String ,dynamic >;void main() { StringDynamicMap stringDynamicMap = { "erdai" :"666" }; print (stringDynamicMap); } {erdai: 666 }typedef MyList<T> = List <T>;void main() { MyList<String > stringList = ["123" ,"456" ]; print (stringList); } [123 , 456 ]
1.3、extension 关键字 extension 作用:给一个类进行方法扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 extension StringExtension on String { int toInt(){ return int .parse(this ); } }void main() { print ('${"666" .toInt().runtimeType} ===> ${"666" .toInt()} ' ); } int ===> 666
1.4、泛型方法 类比 Java,Kotlin 中的泛型方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public <T> void genericMethod(T param){ } fun <T> genericMethod(param: T){ }void genericMethod<T>(T param){ }
不同点:
1、Java 中方法的泛型定义在返回值的前面
2、Kotlin 中的方法泛型定义在方法名的前面
3、Dart 中的泛型定义在方法名的后面
1.5、命名构造方法和 factory 构造方法 如下示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Student { String? name; int? age; Student.nameConstructor(this .name,this .age); static Student? _instance; Student._private(); factory Student(){ return _instance ??= Student._private(); } }void main() { var student = Student.nameConstructor("erdai" , 18 ); var student1 = Student(); }
1.6、getter,setter 语法规则:
get 方法语法格式:返回值类型 get 方法名 { 方法体 }
set 方法语法格式:set 方法名 ( 参数 ) { 方法体 }
如下示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Dog { late String _name; late int _age; Dog(this ._name, this ._age); String get name{ return _name; } set name(String name){ _name = name; } int get age => _age; set age(int value) { _age = value; } String get string{ return 'Dog{_name:$_name ,_age:$_age }' ; } }void main() { var dog = Dog("拉布拉多" ,6 ); print (dog.string); dog.name = "阿拉斯加" ; dog.age = 7 ; print (dog.string); } Dog{_name:拉布拉多,_age:6 } Dog{_name:阿拉斯加,_age:7 }
1.7、mixin 1)、Dart 语言的类是单继承的,如果我们想要实现类似多继承的效果可以使用 mixin 机制,又叫混入机制,例如把类 A 混入到类 B 中,那么类 B 就拥有了类 A 的成员,跟继承的特性非常相似
2)、定义一个可以被 mixin 的类,使用 mixin 关键字代替 class 关键字即可
3)、继承被 mixin 的类,使用 with 关键字,如果有多个,中间用 , 隔开
4)、被 mixin 的类只能继承自 Object,不能继承其他类,且不能有构造方法
5)、父类约束:当声明一个 mixin 时, on 后面的类就是这个 mixin 的父类约束。一个类若是要 with 这个 mixin,则这个类必须继承或实现这个 mixin 的父类约束
6)、就远命中原则:当 with 多个 mixin,多个 mixin 拥有同一个方法,则调用方法时会命中最后一个 mixin 类的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 mixin A{ void getA(){ print ('A' ); } }mixin B{ void getB(){ print ('B' ); } }class C { void getC(){ print ('C' ); } }class CC extends C with A ,B {}void main() { var cc = CC(); cc.getA(); cc.getB(); cc.getC(); print (cc is A); print (cc is B); print (cc is C); } A B Ctrue true true class D {}mixin E extends D{ E(); }class F {}mixin G on F{}class I extends F with G {} mixin F1{}mixin G1 on F1{}class I1 with F1 ,G1 {} mixin Test1{ void testMethod(){ print ('Test1 testMethod' ); } }mixin Test2{ void testMethod(){ print ('Test2 testMethod' ); } }class Test with Test1 ,Test2 { }void main() { var test = Test(); test.testMethod(); } Test2 testMethod
有了上面的这些知识,一会阅读源码就胸有成竹了。
接下来我们先看下 GetX 的状态管理使用,然后在分析源码。
二、GetX 状态管理使用 GetX 状态管理主要有两种使用方式:
1、GetBuilder + Controller.update 状态管理模式
2、Obx + obs 响应式管理模式
2.1、GetBuilder + Controller.update 状态管理模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class GetBuilderLogic extends GetxController { var count = 0 ; void increase(){ count++; update(); } }class GetBuilderPage extends StatelessWidget { GetBuilderPage({Key? key}) : super (key: key); final GetBuilderLogic logic = Get.put(GetBuilderLogic()); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('GetBuilderPage' ), ), body: GetBuilder<GetBuilderLogic>(builder: (logic) { return Center( child: Text( 'You tapped the FAB ${logic.count} times' , style: const TextStyle(fontSize: 20 ), ), ); }), floatingActionButton: FloatingActionButton( onPressed: () => logic.increase(), tooltip: 'Increment Counter' , child: const Icon(Icons.add), ), floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, ); } }
效果展示:
2.2、Obx + obs 响应式管理模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class ObxLogic { var count = 0. obs; void increase(){ count++; } }class ObxPage extends StatelessWidget { ObxPage({Key? key}) : super (key: key); final ObxLogic logic = Get.put(ObxLogic()); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('ObxPage' ), ), body: Obx(() { return Center( child: Text( 'You clicked the FAB ${logic.count} times' , style: const TextStyle(fontSize: 20 ), ), ); }), floatingActionButton: FloatingActionButton( onPressed: () => logic.increase(), tooltip: 'Increment Counter' , child: const Icon(Icons.add), ), floatingActionButtonLocation: FloatingActionButtonLocation .endFloat, ); } }
效果展示:
三、GetX 状态管理源码分析 上面无论是 GetBuilder 还是 Obx 模式,其实就是对观察者模式 的一个应用。
仔细分析,他们都有一些共同点:
1、创建一个 logic
GetBuilderLogic 继承了 GetxController,实际它就变成了一个被观察者,然后调用 GetxController 的 update 方法通知观察者去更新 UI
ObxLogic 虽没有继承 GetxController,但给变量添加了.obs
后缀,使得它变成了一个响应式变量(被观察者),当它改变的时候就会通知观察者刷新 UI
2、使用 Get.put 方法进行依赖注入,对 logic 进行管理
3、GetBuilder 使用 GetBuilder 管理模式,内部做的主要事情:
1、从 Get 中取出依赖注入的实例,建立观察者和被观察者的绑定关系
2、对 StatefulWidget 进行了封装,最终还是通过 setState 去进行状态的更新
4、Obx 使用 Obx 管理模式,内部做的主要事情:
1、使用了一个中间层 RxInterface 建立观察者和被观察者的绑定关系
2、对 StatefulWidget 进行了封装,最终还是通过 setState 去进行状态的更新
接下来我们正式进入源码分析。
3.1、依赖注入管理 从 Get.put 为入口进行分析:
1 2 3 4 5 6 S put<S>(S dependency, {String? tag, bool permanent = false , InstanceBuilderCallback<S>? builder}) => GetInstance().put<S>(dependency, tag: tag, permanent: permanent);
可以看到:
1、这是一个泛型方法。后续我们需要通过泛型类型 + tag 去生成存储依赖注入实例的 key
2、内部使用了桥接模式 ,将具体实现交给了 GetInstance
接着看 GetInstance,仅贴出关键代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 class GetInstance { factory GetInstance() => _getInstance ??= const GetInstance._(); const GetInstance._(); static GetInstance? _getInstance; static final Map <String , _InstanceBuilderFactory> _singl = {}; S put<S>( S dependency, { String? tag, bool permanent = false , @deprecated InstanceBuilderCallback<S>? builder, }) { _insert( isSingleton: true , name: tag, permanent: permanent, builder: builder ?? (() => dependency)); return find<S>(tag: tag); } void _insert<S>({ bool? isSingleton, String? name, bool permanent = false , required InstanceBuilderCallback<S> builder, bool fenix = false , }) { final key = _getKey(S, name); _singl[key] = _InstanceBuilderFactory<S>( isSingleton, builder, permanent, false , fenix, name, ); } String _getKey(Type type, String? name) { return name == null ? type.toString() : type.toString() + name; } S find<S>({String? tag}) { final key = _getKey(S, tag); if (isRegistered<S>(tag: tag)) { final dep = _singl[key]; if (dep == null ) { if (tag == null ) { throw 'Class "$S " is not registered' ; } else { throw 'Class "$S " with tag "$tag " is not registered' ; } } final i = _initDependencies<S>(name: tag); return i ?? dep.getDependency() as S; } } bool isRegistered<S>({String? tag}) => _singl.containsKey(_getKey(S, tag)); }
上述代码:
1、GetInstance 是一个单例类
2、put 方法会先调用内部的 insert 方法,然后在通过 find 查找实例
3、insert 方法会根据传入的泛型 + tag
生成 key,然后创建依赖注入实例工厂,最后放入到 map 中
4、key 生成的规则:
1、如果传入的 tag 为空,则 key 为传入的泛型
2、如果 tag 不为空,则 key 为传入的泛型 + tag
5、find 方法会根据传入的tag和泛型
生成 key,并通过 key 从 map 中去取依赖注入实例工厂,如果能够取到,则通过工厂方法模式 创建具体实例并返回
ok,上述我们分析了 Get.put 方法,实际上还有 delete,lazyPut 等方法,当我们的页面销毁时,GetX 会自动给我们进行实例的回收,具体代码就不贴了,感兴趣的可以去看下。
3.1、GetBuilder + Controller.update 状态管理模式 接着看 GetxController 里面做了啥,为什么继承它就能成为一个被观察者?
上源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 abstract class GetxController extends DisposableInterface with ListenableMixin , ListNotifierMixin { void update([List <Object >? ids, bool condition = true ]) { if (!condition) { return ; } if (ids == null ) { refresh(); } else { for (final id in ids) { refreshGroup(id); } } } }
可以看到:
1、GetxController 内部就一个 update 方法,主要逻辑:
1、通知观察者刷新 UI:根据观察者是否设置了 id 更新 ui
2、如果传入了 id,则只通知设置了该 id 的观察者,如果没有,则通知所有的观察者
2、update 内部调用的是 refresh 系列方法,这是 ListNotifierMixin 给它提供的,实际就是因为 with 了 ListNotifierMixin 才让它成为了一个被观察者
继续跟进 ListNotifierMixin :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 mixin ListNotifierMixin on ListenableMixin { List <GetStateUpdate?>? _updaters = <GetStateUpdate?>[]; HashMap<Object? , List <GetStateUpdate>>? _updatersGroupIds = HashMap<Object? , List <GetStateUpdate>>(); @protected void refresh() { assert (_debugAssertNotDisposed()); _notifyUpdate(); } void _notifyUpdate() { for (var element in _updaters!) { element!(); } } void _notifyIdUpdate(Object id) { if (_updatersGroupIds!.containsKey(id)) { final listGroup = _updatersGroupIds![id]!; for (var item in listGroup) { item(); } } } @protected void refreshGroup(Object id) { assert (_debugAssertNotDisposed()); _notifyIdUpdate(id); } @override void removeListener(VoidCallback listener) { assert (_debugAssertNotDisposed()); _updaters!.remove(listener); } void removeListenerId(Object id, VoidCallback listener) { assert (_debugAssertNotDisposed()); if (_updatersGroupIds!.containsKey(id)) { _updatersGroupIds![id]!.remove(listener); } _updaters!.remove(listener); } @override Disposer addListener(GetStateUpdate listener) { assert (_debugAssertNotDisposed()); _updaters!.add(listener); return () => _updaters!.remove(listener); } Disposer addListenerId(Object? key, GetStateUpdate listener) { _updatersGroupIds![key] ??= <GetStateUpdate>[]; _updatersGroupIds![key]!.add(listener); return () => _updatersGroupIds![key]!.remove(listener); } }
上述代码不就是典型的被观察者的实现吗?
1、GetStateUpdate 就是观察者,实际它就是一个回调,使用了 typedef 进行定义:
1 typedef GetStateUpdate = void Function ();
2、内部封装了添加,删除,通知观察者等一系列的操作,还不懂被观察者模式的可以看我这篇文章传送门 。
ok,现在我们已经有了被观察者,接下来看看它是如何添加观察者。
GetBuilder 源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 class GetBuilder <T extends GetxController > extends StatefulWidget { @override GetBuilderState<T> createState() => GetBuilderState<T>(); }class GetBuilderState <T extends GetxController > extends State <GetBuilder <T >> with GetStateUpdaterMixin { T? controller; Object? _filter; @override void initState() { super .initState(); var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag); if (widget.global) { if (isRegistered) { controller = GetInstance().find<T>(tag: widget.tag); } } _subscribeToController(); } void _subscribeToController() { _remove?.call(); _remove = (widget.id == null ) ? controller?.addListener( _filter != null ? _filterUpdate : getUpdate, ) : controller?.addListenerId( widget.id, _filter != null ? _filterUpdate : getUpdate, ); } void _filterUpdate() { var newFilter = widget.filter!(controller!); if (newFilter != _filter) { _filter = newFilter; getUpdate(); } } @override void dispose() { super .dispose(); widget.dispose?.call(this ); if (_isCreator! || widget.assignId) { if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) { GetInstance().delete<T>(tag: widget.tag); } } @override Widget build(BuildContext context) { return widget.builder(controller!); } }mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> { void getUpdate() { if (mounted) setState(() {}); } }
可以看到:
1、GetBuilder 对 StatefulWidget 进行了封装,具体逻辑在 GetBuilderState 中
2、GetBuilderState 中:
1、根据泛型和tag
生成 key,然后去取依赖注入实例
2、根据 id 是否为 null 进行观察者(getUpdate)的添加
3、当页面销毁时,移除依赖注入的实例
3、getUpdate 的具体实现在 GetStateUpdaterMixin 中,可以看到最终还是调用 setState 进行 UI 的更新
当我们点击 button,就会调用 update 方法,通知观察者进行 UI 的刷新。
ok,至此就完成了 GetBuilder + Controller.update 状态管理模式的源码分析。
3.2、Obx + obs 响应式管理模式 我们从0.obs
为入口进行分析:
1 2 3 extension IntExtension on int { RxInt get obs => RxInt(this ); }
可以看到它是 int 的一个扩展方法,内部定义了一个 get 方法,get 方法调用了 RxInt。
跟进到 RxInt:
1 2 3 4 5 6 7 8 9 10 11 12 13 class RxInt extends Rx <int > { RxInt(int initial) : super (initial); RxInt operator +(int other) { value = value + other; return this ; } RxInt operator -(int other) { value = value - other; return this ; } }
上述代码:
1、RxInt 继承了 Rx 泛型类
2、进行了操作符(+,-)的重载
继续看 Rx:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 class Rx <T > extends _RxImpl <T > { Rx(T initial) : super (initial); }abstract class _RxImpl <T > extends RxNotifier <T > with RxObjectMixin <T > { }class RxNotifier <T > = RxInterface <T > with NotifyManager <T >;//GetStream :被观察者的具体实现 class GetStream <T > { void _notifyData(T data) { _isBusy = true ; for (final item in _onData!) { if (!item.isPaused) { item._data?.call(data); } } _isBusy = false ; } void add(T event) { _value = event; _notifyData(event); } LightSubscription<T> listen(void Function (T event) onData, {Function? onError, void Function ()? onDone, bool? cancelOnError}) { final subs = LightSubscription<T>( removeSubscription, onPause: onPause, onResume: onResume, onCancel: onCancel, ) ..onData(onData) ..onError(onError) ..onDone(onDone) ..cancelOnError = cancelOnError; addSubscription(subs); onListen?.call(); return subs; } }mixin NotifyManager<T> { GetStream<T> subject = GetStream<T>(); bool get canUpdate => _subscriptions.isNotEmpty; void addListener(GetStream<T> rxGetx) { if (!_subscriptions.containsKey(rxGetx)) { final subs = rxGetx.listen((data) { if (!subject.isClosed) subject.add(data); }); } } StreamSubscription<T> listen( void Function (T) onData, { Function? onError, void Function ()? onDone, bool? cancelOnError, }) => subject.listen( onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError ?? false , ); }abstract class RxInterface <T > { static RxInterface? proxy; bool get canUpdate; void addListener(GetStream<T> rxGetx); void close(); StreamSubscription<T> listen(void Function (T event) onData, {Function? onError, void Function ()? onDone, bool? cancelOnError}); static T notifyChildren<T>(RxNotifier observer, ValueGetter<T> builder) { final _observer = RxInterface.proxy; RxInterface.proxy = observer; final result = builder(); RxInterface.proxy = _observer; return result; } }mixin RxObjectMixin<T> on NotifyManager<T> { late T _value; bool firstRebuild = true ; set value(T val) { if (_value == val && !firstRebuild) return ; firstRebuild = false ; _value = val; subject.add(_value); } T get value { RxInterface.proxy?.addListener(subject); return _value; } }
看了上述代码你可能会有一些头晕,现在我们好好理一下整个流程:
当我们进入页面调用0.obs
的时候,最终会触发 RxObjectMixin 中的 get 方法, RxObjectMixin 中的 get 方法内部会走:
1 2 3 4 5 6 7 8 9 10 11 RxInterface.proxy?.addListener(subject);void addListener(GetStream<T> rxGetx) { if (!_subscriptions.containsKey(rxGetx)) { final subs = rxGetx.listen((data) { if (!subject.isClosed) subject.add(data); }); } }
留个疑问🤔️:RxInterface.proxy 是在哪里被赋值的呢?
这里实则有两层被观察者关系的绑定,一层是传入的被观察者,一层是 NotifyManager 内部持有的被观察者:
1、传入的被观察者会进行添加观察者的操作
2、观察者内部又会触发内部持有的被观察者发送事件通知它所绑定的观察者
画个图理一理:
那么内部持有的被观察者在哪里进行了观察者的添加呢?
想要知道答案,就要看看 Obx 的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 class Obx extends ObxWidget { final WidgetCallback builder; const Obx(this .builder); @override Widget build() => builder(); }abstract class ObxWidget extends StatefulWidget { @override _ObxState createState() => _ObxState(); }class _ObxState extends State <ObxWidget > { final _observer = RxNotifier(); late StreamSubscription subs; @override void initState() { super .initState(); subs = _observer.listen(_updateTree, cancelOnError: false ); } void _updateTree(_) { if (mounted) { setState(() {}); } } @override void dispose() { subs.cancel(); _observer.close(); super .dispose(); } @override Widget build(BuildContext context) => RxInterface.notifyChildren(_observer, widget.build); }
上述代码可以看到:
1、完成了 Rx 内部被观察者和观察者的绑定,观察者内部还是调用 setState 进行状态的更新
2、通过 RxInterface.notifyChildren 方法完成 RxInterface.proxy 的赋值
这里也就回答了我们上面留的疑问。
但又出现了另外一个问题:RxInterface.proxy 是一个静态变量,如果使用不当会造成内存泄漏,那 GetX 是怎么做的呢?
具体在看一眼 RxInterface.notifyChildren 方法:
1 2 3 4 5 6 7 8 static T notifyChildren<T>(RxNotifier observer, ValueGetter<T> builder) { final _observer = RxInterface.proxy; RxInterface.proxy = observer; final result = builder(); RxInterface.proxy = _observer; return result; }
可以看到:
1、将传入的 observer 赋值给 RxInterface.proxy
2、进行页面视图的构建
3、待页面构建完成,又将 RxInterface.proxy 置为 null
上述操作就避免了 RxInterface.proxy 内存泄漏,也让整个逻辑形成了闭环。
当我们执行 count++ 操作时:
1 2 3 4 5 6 7 8 class ObxLogic { var count = 0. obs; void increase(){ count++; } }
会调用 RxObjectMixin 的 set 方法通知观察者,观察者内部会执行 setState 方法,setState 会调用页面的 build 方法,build 中会调用 RxInterface.notifyChildren ,最终完成 UI 的刷新。
四、总结 本篇文章我们介绍了:
1、GetX 源码分析需要的一些前置知识:函数类型,typedef,extension,泛型方法,构造方法,get,set,mixin
2、GetX 状态管理的使用及效果展示,主要分为两种:
1、GetBuilder + Controller.update 状态管理模式
2、Obx + obs 响应式管理模式
3、进行了 GetX 状态管理的源码分析
1、GetX 的依赖注入,内部使用 map 进行管理
2、GetBuilder + Controller.update 源码:主要通过 Get 的依赖注入管理完成观察者和被观察者的绑定,最终还是通过 setState 进行状态的更新
3、Obx + obs 源码:主要通过 RxInterface 完成观察者和被观察者关系的绑定,最终还是通过 setState 进行状态的更新
好了,本篇文章到这里就结束了,希望能给你带来帮助 🤝
感谢你阅读这篇文章
下篇预告 下篇文章我会手撸 GetX 状态管理核心源码实现,敬请期待吧🍺
参考和推荐 Flutter GetX 深度剖析
你的点赞,评论,是对我巨大的鼓励!
欢迎关注我的公众号: sweetying ,文章更新可第一时间收到
如果有问题 ,公众号内有加我微信的入口,在技术学习、个人成长的道路上,我们一起前进!