前言 GetX 是 Flutter 上一个轻量且强大的状态管理框架,它不仅包含了状态管理 ,还有路由管理,主题管理,国际化多语言管理,网络请求,数据验证,Dialog,Snackbar 等功能,在一定程度上,减少了我们的开发时间,提高了工作效率。这么好用的一个框架,让我们来学习一下吧。
在我看来,GetX 最核心也是最具有特色的功能是它的状态管理功能,因此今天我们主要的任务就是把 GetX 的状态管理功能给整明白,下面我也会 Face to Face 带领大家去手撸 GetX 状态管理的核心源码实现。
问题 为了让大家更好的去理解,在此,我先抛出几个问题,大家可以去思考一下?
1、你了解 Dart 中的函数类型吗?怎么定义?
2、typedef 关键字的作用是什么?
3、extension 关键字的作用是什么?
4、如何定义一个泛型方法?Dart 中的泛型方法和 Java,Kotlin 有啥区别?
5、你了解 Dart 中的命名构造方法和 factory 构造方法吗?
6、你知道 Dart 中的 getter,setter 方法要怎么写吗?
如果你心里对于上面的这些问题有疑问🤔️,那么就跟着我的步伐继续往下走吧
一、Dart 中的函数类型 函数类型的定义:将一个函数当作类型的类型就是函数类型,它可以:
1、作为一个函数的参数或返回值
2、赋值给一个变量
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.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
二、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 ]
三、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
四、泛型方法 类比 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 中的泛型定义在方法名的后面
五、命名构造方法和 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(); }
六、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 }
七、GetX 状态管理源码分析 7.1、依赖注入管理 1、使用桥接模式,将具体实现交由 GetInstance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 extension Inst on GetInterface { S put<S>(S dependency, {String? tag, bool permanent = false , InstanceBuilderCallback<S>? builder}) => GetInstance().put<S>(dependency, tag: tag, permanent: permanent); S find<S>({String? tag}) => GetInstance().find<S>(tag: tag); Future<bool > delete<S>({String? tag, bool force = false }) async => GetInstance().delete<S>(tag: tag, force: force); }
2、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 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, }){ } S find<S>({String? tag}) { } bool delete<S>({String? tag, String? key, bool force = false }) { } String _getKey(Type type, String? name) { return name == null ? type.toString() : type.toString() + name; } }class _InstanceBuilderFactory <S > { S? dependency; }
7.2、GetBuilder + Controller.update 状态管理模式 1、GetxController(被观察者) 1 2 3 4 5 6 7 8 9 abstract class GetxController extends DisposableInterface with ListenableMixin , ListNotifierMixin { void update([List <Object >? ids, bool condition = true ]) { } }
2、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 mixin ListNotifierMixin on ListenableMixin { List <GetStateUpdate?>? _updaters = <GetStateUpdate?>[]; HashMap<Object? , List <GetStateUpdate>>? _updatersGroupIds = HashMap<Object? , List <GetStateUpdate>>(); 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(); } } } @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); } @mustCallSuper void dispose() { _updaters = null ; _updatersGroupIds = null ; } @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); } }
3、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 class GetBuilder <T extends GetxController > extends StatefulWidget { final GetControllerBuilder<T> builder; final Object? id; final String? tag; final bool autoRemove; const GetBuilder({ Key? key, required this .builder, this .autoRemove = true , this .tag, this .id, }) : super (key: key); @override GetBuilderState<T> createState() => GetBuilderState<T>(); }class GetBuilderState <T extends GetxController > extends State <GetBuilder <T >> with GetStateUpdaterMixin { T? controller; bool? _isCreator = false ; VoidCallback? _remove; @override void initState() { super .initState(); var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag); if (isRegistered) { if (GetInstance().isPrepared<T>(tag: widget.tag)) { _isCreator = true ; } else { _isCreator = false ; } controller = GetInstance().find<T>(tag: widget.tag); } else { controller = widget.init; _isCreator = true ; GetInstance().put<T>(controller!, tag: widget.tag); } _subscribeToController(); } void _subscribeToController() { widget.id == null ? controller?.addListener( _filter != null ? _filterUpdate : getUpdate,): controller?.addListenerId(widget.id, _filter != null ? _filterUpdate : 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); } } _remove?.call(); controller = null ; _isCreator = null ; _remove = null ; _filter = null ; } @override Widget build(BuildContext context) { return widget.builder(controller!); } }
7.3、Obx + obs 响应式管理模式 1、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 extension IntExtension on int { RxInt get obs => RxInt(this ); }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 ; } }class Rx <T > extends _RxImpl <T > { Rx(T initial) : super (initial); }abstract class _RxImpl <T > extends RxNotifier <T > with RxObjectMixin <T > { _RxImpl(T initial) { _value = initial; } }
2、监听管理
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 class RxNotifier <T > = RxInterface <T > with NotifyManager <T >;abstract class RxInterface <T > { static RxInterface? proxy; static T notifyChildren<T>(RxNotifier observer, ValueGetter<T> builder) { final _observer = RxInterface.proxy; RxInterface.proxy = observer; final result = builder(); if (!observer.canUpdate) { RxInterface.proxy = _observer; throw """ [Get] the improper use of a GetX has been detected. You should only use GetX or Obx for the specific widget that will be updated. If you are seeing this error, you probably did not insert any observable variables into GetX/Obx or insert them outside the scope that GetX considers suitable for an update (example: GetX => HeavyWidget => variableObservable). If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX. """ ; } RxInterface.proxy = _observer; return result; } }mixin NotifyManager<T> { GetStream<T> subject = GetStream<T>(); final _subscriptions = <GetStream, List <StreamSubscription>>{}; 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); }); final listSubscriptions = _subscriptions[rxGetx] ??= <StreamSubscription>[]; listSubscriptions.add(subs); } } StreamSubscription<T> listen( void Function (T) onData, { Function? onError, void Function ()? onDone, bool? cancelOnError, }) => subject.listen( onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError ?? false , ); }
3、RxObjectMixin
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 mixin RxObjectMixin<T> on NotifyManager<T> { late T _value; bool firstRebuild = true ; bool sentToStream = false ; String get string => value.toString(); @override String toString() => value.toString(); set value(T val) { if (subject.isClosed) return ; sentToStream = false ; if (_value == val && !firstRebuild) return ; firstRebuild = false ; _value = val; sentToStream = true ; subject.add(_value); } T get value { RxInterface.proxy?.addListener(subject); return _value; } }
4、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 52 class Obx extends ObxWidget { final WidgetCallback builder; const Obx(this .builder); @override Widget build() => builder(); }abstract class ObxWidget extends StatefulWidget { const ObxWidget({Key? key}) : super (key: key); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super .debugFillProperties(properties); properties..add(ObjectFlagProperty<Function >.has('builder' , build)); } @override _ObxState createState() => _ObxState(); @protected Widget build(); }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); }
八、手撸 GetX 状态管理核心源码实现 8.1、依赖注入管理核心源码实现 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 class Mobx { static S put<S>(S dependency,{String? tag}){ return MobxInstance().put<S>(dependency,tag: tag); } static S find<S>({String? tag}){ return MobxInstance().find<S>(tag: tag); } static bool delete<S>({String? tag}){ return MobxInstance().delete<S>(tag: tag); } }class _InstanceBuilderFactory <T > { T dependency; _InstanceBuilderFactory(this .dependency); }class MobxInstance { static MobxInstance? instance; MobxInstance._(); factory MobxInstance() => instance ??= MobxInstance._(); final _single = <String ,_InstanceBuilderFactory>{}; String _getKey(Type type,String? tag){ return tag == null ? type.toString() : type.toString() + tag; } S put<S>(S dependency,{String? tag}){ final newKey = _getKey(S, tag); _single.putIfAbsent(newKey, () => _InstanceBuilderFactory(dependency)); return find<S>(tag: tag); } S find<S>({String? tag}){ final newKey = _getKey(S, tag); if (_single.containsKey(newKey)){ return _single[newKey]!.dependency; } throw '"$newKey " not found' ; } bool delete<S>({String? tag}){ final newKey = _getKey(S, tag); if (_single.containsKey(newKey)){ _single.remove(newKey); print ('"$newKey " removed success' ); return true ; } print ('"$newKey " Already removed' ); return false ; } }
8.2、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 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 typedef MobXCallback = void Function ();mixin MobxNotifier{ final _updaters = <MobXCallback>[]; final _updatersGroupIds = <Object? ,List <MobXCallback>>{}; void notifyUpdate(){ if (_updaters.isNotEmpty){ for (var element in _updaters) { element(); } } } void notifyIdUpdate(Object? id){ if (_updatersGroupIds.isEmpty)return ; if (_updatersGroupIds.containsKey(id)){ var listGroup = _updatersGroupIds[id]; listGroup?.forEach((element) { element(); }); } } void removeListener(MobXCallback callback){ if (_updaters.contains(callback)){ _updaters.remove(callback); } } void removeListenerId(Object? id,MobXCallback callback){ if (_updatersGroupIds.containsKey(id)){ _updatersGroupIds[id]?.remove(callback); } _updaters.remove(callback); } void addListener(MobXCallback callback){ _updaters.add(callback); } void addListenerId(Object? id,MobXCallback callback){ _updatersGroupIds[id] ??= <MobXCallback>[]; _updatersGroupIds[id]?.add(callback); } void dispose(){ print ('notifier dispose' ); _updaters.clear(); _updatersGroupIds.clear(); } }class MobxController with MobxNotifier { void update([List <Object >? ids]) { if (ids == null ) { notifyUpdate(); } else { for (var element in ids) { notifyIdUpdate(element); } } } }typedef MobControllerBuilder<T extends MobxController> = Widget Function (T controller);class MobxBuilder <T extends MobxController > extends StatefulWidget { final MobControllerBuilder<T> builder; final Object? id; final String? tag; final bool autoRemove; const MobxBuilder({Key? key, required this .builder, this .id, this .tag, this .autoRemove = true }) : super (key: key); @override State<MobxBuilder> createState() => _MobxBuilderState<T>(); }class _MobxBuilderState <T extends MobxController > extends State <MobxBuilder <T >> { late T controller; @override void initState() { super .initState(); controller = MobxInstance().find<T>(tag: widget.tag); if (widget.id == null ){ controller.addListener(() { if (mounted){ setState(() { }); } }); }else { controller.addListenerId(widget.id, () { if (mounted){ setState(() { }); } }); } } @override void dispose() { if (widget.autoRemove){ MobxInstance().delete(tag: widget.tag); } controller.dispose(); super .dispose(); } @override Widget build(BuildContext context) { return widget.builder(controller); } }
8.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 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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 import 'package:flutter/material.dart' ;typedef MyVoidCallback = void Function ();typedef MyValueGetter<T> = T Function ();class MyRxObservable { final listeners = <MyVoidCallback>[]; void add(MyVoidCallback listener) => listeners.add(listener); void remove(MyVoidCallback listener) => listeners.remove(listener); void notify(){ for (var value in listeners) { value(); } } void dispose(){ listeners.clear(); } }class MyRxNotifier { static MyRxNotifier? proxy; final myRxObservable = MyRxObservable(); final map = <MyRxObservable,String >{}; bool get canUpdate => map.isNotEmpty; void addListener(MyRxObservable observable){ if (!map.containsKey(observable)){ observable.add(() { myRxObservable.notify(); }); map[observable] = '' ; } } static T notifyChildren<T>(MyRxNotifier myRxNotifier,MyValueGetter<T> builder){ final _observer = MyRxNotifier.proxy; MyRxNotifier.proxy = myRxNotifier; final result = builder(); if (!myRxNotifier.canUpdate){ MyRxNotifier.proxy = _observer; throw 'nofityChildren error exception' ; } MyRxNotifier.proxy = _observer; return result; } }abstract class MyRx <T > { MyRxObservable myRxObservable = MyRxObservable(); bool firstRebuild = true ; T _value; MyRx(this ._value); set value(T value){ if (_value == value && !firstRebuild)return ; firstRebuild = false ; _value = value; myRxObservable.notify(); } T get value{ MyRxNotifier.proxy?.addListener(myRxObservable); return _value; } }class MyRxInt extends MyRx <int > { MyRxInt(int value) : super (value); MyRxInt operator +(int num ){ value = value + num ; return this ; } MyRxInt operator -(int num ){ value = value - num ; return this ; } }extension MyIntExtension on int { MyRxInt get mbx => MyRxInt(this ); }class Mbx extends StatefulWidget { final MyValueGetter<Widget> builder; const Mbx(this .builder,{Key? key}) : super (key: key); @override State<Mbx> createState() => _MbxState(); }class _MbxState extends State <Mbx > { MyRxNotifier myRxNotifier = MyRxNotifier(); @override void initState() { super .initState(); myRxNotifier.myRxObservable.add(() { if (mounted){ setState(() { }); } }); } @override Widget build(BuildContext context) { return MyRxNotifier.notifyChildren(myRxNotifier, widget.builder); } }class MyEasyBindWidget extends StatefulWidget { const MyEasyBindWidget( {Key? key, this .bind, this .tag, this .binds, this .tags, required this .child}) : super (key: key); final Object? bind; final String? tag; final List <Object >? binds; final List <String >? tags; final Widget child; @override State<MyEasyBindWidget> createState() => _MyEasyBindWidgetState(); }class _MyEasyBindWidgetState extends State <MyEasyBindWidget > { @override Widget build(BuildContext context) { return widget.child; } @override void dispose() { _closeController(); _closeControllers(); super .dispose(); } void _closeController() { if (widget.bind == null ){ return ; } var key = widget.bind.runtimeType.toString() + (widget.tag ?? '' ); MyEasy.delete(key: key); } void _closeControllers() { if (widget.binds == null ){ return ; } for (int i = 0 ; i < widget.binds!.length; i++){ var type = widget.binds![i].runtimeType.toString(); if (widget.tags == null || widget.tags?.isEmpty == true ){ MyEasy.delete(key: type); }else { var key = type + (widget.tags![i]); MyEasy.delete(key: key); } } } }