Rodrigo Lopez Peker

- Added some comment docs to several methods in GetInstance() and extension_instance.dart (WIP)

- Added a fix (a little bit hacky) on DisposableInterface (rx_interface.dart), to prevent method overriding in subclasses, preventing devs to break the lifecycle of Controllers. This compensates the lack of `final` methods in Dart, or the inability to limit the scope of methods to internal packages.
@@ -11,12 +11,36 @@ extension Inst on GetInterface { @@ -11,12 +11,36 @@ extension Inst on GetInterface {
11 {String tag, bool permanent = false}) async => 11 {String tag, bool permanent = false}) async =>
12 GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent); 12 GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
13 13
  14 + /// Creates a new Instance<[S]> from the <[S]>[builder] callback.
  15 + /// Every time [find]<[S]>() is used, it calls the builder method to generate
  16 + /// a new Instance [S].
  17 + ///
  18 + /// Example:
  19 + ///
  20 + /// ```create(() => Repl());
  21 + /// Repl a = find();
  22 + /// Repl b = find();
  23 + /// print(a==b); (false)```
  24 + ///
14 void create<S>(FcBuilderFunc<S> builder, 25 void create<S>(FcBuilderFunc<S> builder,
15 {String name, bool permanent = true}) => 26 {String name, bool permanent = true}) =>
16 GetInstance().create<S>(builder, name: name, permanent: permanent); 27 GetInstance().create<S>(builder, name: name, permanent: permanent);
17 28
  29 + /// Finds a instance of the required Class<[S]> (or [tag])
  30 + /// In the case of using Get.[create], it will create an instance
  31 + /// each time you call [find]
  32 + ///
18 S find<S>({String tag}) => GetInstance().find<S>(tag: tag); 33 S find<S>({String tag}) => GetInstance().find<S>(tag: tag);
19 34
  35 + /// Injects a Instance [S] in [GetInstance].
  36 + ///
  37 + /// No need to define the generic type <[S]> as it's inferred from the [dependency]
  38 + ///
  39 + /// - [dependency] The Instance to be injected.
  40 + /// - [tag] optionally, use a [tag] as an "id" to create multiple records of the same Type<[S]>
  41 + /// - [permanent] keeps the Instance in memory, not following [GetConfig.smartManagement]
  42 + /// rules
  43 + ///
20 S put<S>(S dependency, 44 S put<S>(S dependency,
21 {String tag, bool permanent = false, FcBuilderFunc<S> builder}) => 45 {String tag, bool permanent = false, FcBuilderFunc<S> builder}) =>
22 GetInstance() 46 GetInstance()
@@ -39,7 +39,15 @@ class GetInstance { @@ -39,7 +39,15 @@ class GetInstance {
39 return put<S>(await builder(), tag: tag, permanent: permanent); 39 return put<S>(await builder(), tag: tag, permanent: permanent);
40 } 40 }
41 41
42 - /// Inject class on Get Instance Manager 42 + /// Injects a Instance [S] in [GetInstance].
  43 + ///
  44 + /// No need to define the generic type <[S]> as it's inferred from the [dependency]
  45 + ///
  46 + /// - [dependency] The Instance to be injected.
  47 + /// - [tag] optionally, use a [tag] as an "id" to create multiple records of the same Type<[S]>
  48 + /// - [permanent] keeps the Instance in memory, not following [GetConfig.smartManagement]
  49 + /// rules.
  50 + ///
43 S put<S>( 51 S put<S>(
44 S dependency, { 52 S dependency, {
45 String tag, 53 String tag,
@@ -54,12 +62,17 @@ class GetInstance { @@ -54,12 +62,17 @@ class GetInstance {
54 return find<S>(tag: tag); 62 return find<S>(tag: tag);
55 } 63 }
56 64
57 - /// Create a new instance from builder class  
58 - /// Example  
59 - /// create(() => Repl()); 65 + /// Creates a new Class Instance [S] from the builder callback[S].
  66 + /// Every time [find]<[S]>() is used, it calls the builder method to generate
  67 + /// a new Instance [S].
  68 + ///
  69 + /// Example:
  70 + ///
  71 + /// ```create(() => Repl());
60 /// Repl a = find(); 72 /// Repl a = find();
61 /// Repl b = find(); 73 /// Repl b = find();
62 - /// print(a==b); (false) 74 + /// print(a==b); (false)```
  75 + ///
63 void create<S>( 76 void create<S>(
64 FcBuilderFunc<S> builder, { 77 FcBuilderFunc<S> builder, {
65 String name, 78 String name,
@@ -69,6 +82,8 @@ class GetInstance { @@ -69,6 +82,8 @@ class GetInstance {
69 isSingleton: false, name: name, builder: builder, permanent: permanent); 82 isSingleton: false, name: name, builder: builder, permanent: permanent);
70 } 83 }
71 84
  85 + /// Injects the Instance [S] builder into the [_singleton] HashMap.
  86 + ///
72 void _insert<S>({ 87 void _insert<S>({
73 bool isSingleton, 88 bool isSingleton,
74 String name, 89 String name,
@@ -76,14 +91,17 @@ class GetInstance { @@ -76,14 +91,17 @@ class GetInstance {
76 FcBuilderFunc<S> builder, 91 FcBuilderFunc<S> builder,
77 }) { 92 }) {
78 assert(builder != null); 93 assert(builder != null);
79 - String key = _getKey(S, name);  
80 - 94 + final key = _getKey(S, name);
81 _singl.putIfAbsent( 95 _singl.putIfAbsent(
82 key, () => FcBuilder<S>(isSingleton, builder, permanent, false)); 96 key, () => FcBuilder<S>(isSingleton, builder, permanent, false));
83 } 97 }
84 98
  99 + /// Clears from memory registered Instances associated with [routeName] when
  100 + /// using [GetConfig.smartManagement] as [SmartManagement.full] or [SmartManagement.keepFactory]
  101 + /// Meant for internal usage of [GetPageRoute] and [GetDialogRoute]
  102 + ///
85 Future<void> removeDependencyByRoute(String routeName) async { 103 Future<void> removeDependencyByRoute(String routeName) async {
86 - List<String> keysToRemove = []; 104 + final keysToRemove = <String>[];
87 _routesKey.forEach((key, value) { 105 _routesKey.forEach((key, value) {
88 if (value == routeName) { 106 if (value == routeName) {
89 keysToRemove.add(key); 107 keysToRemove.add(key);
@@ -99,32 +117,41 @@ class GetInstance { @@ -99,32 +117,41 @@ class GetInstance {
99 keysToRemove.clear(); 117 keysToRemove.clear();
100 } 118 }
101 119
102 - bool initDependencies<S>({String name}) {  
103 - String key = _getKey(S, name); 120 + /// Initializes the dependencies for a Class Instance [S] (or tag),
  121 + /// If its a Controller, it starts the lifecycle process.
  122 + /// Optionally associating the current Route to the lifetime of the instance,
  123 + /// if [GetConfig.smartManagement] is marked as [SmartManagement.full] or
  124 + /// [GetConfig.keepFactory]
  125 + ///
  126 + bool _initDependencies<S>({String name}) {
  127 + final key = _getKey(S, name);
104 bool isInit = _singl[key].isInit; 128 bool isInit = _singl[key].isInit;
105 if (!isInit) { 129 if (!isInit) {
106 - startController<S>(tag: name); 130 + _startController<S>(tag: name);
107 _singl[key].isInit = true; 131 _singl[key].isInit = true;
108 if (GetConfig.smartManagement != SmartManagement.onlyBuilder) { 132 if (GetConfig.smartManagement != SmartManagement.onlyBuilder) {
109 - registerRouteInstance<S>(tag: name); 133 + _registerRouteInstance<S>(tag: name);
110 } 134 }
111 } 135 }
112 return true; 136 return true;
113 } 137 }
114 138
115 - void registerRouteInstance<S>({String tag}) { 139 + /// Links a Class instance [S] (or [tag]) to the current route.
  140 + /// Requires usage of [GetMaterialApp].
  141 + ///
  142 + void _registerRouteInstance<S>({String tag}) {
116 _routesKey.putIfAbsent(_getKey(S, tag), () => GetConfig.currentRoute); 143 _routesKey.putIfAbsent(_getKey(S, tag), () => GetConfig.currentRoute);
117 } 144 }
118 145
  146 + /// Finds and returns a Class instance [S] (or tag) without further processing.
119 S findByType<S>(Type type, {String tag}) { 147 S findByType<S>(Type type, {String tag}) {
120 String key = _getKey(type, tag); 148 String key = _getKey(type, tag);
121 return _singl[key].getDependency() as S; 149 return _singl[key].getDependency() as S;
122 } 150 }
123 151
124 - void startController<S>({String tag}) {  
125 - String key = _getKey(S, tag); 152 + void _startController<S>({String tag}) {
  153 + final key = _getKey(S, tag);
126 final i = _singl[key].getDependency(); 154 final i = _singl[key].getDependency();
127 -  
128 if (i is DisposableInterface) { 155 if (i is DisposableInterface) {
129 i.onStart(); 156 i.onStart();
130 GetConfig.log('[GETX] $key has been initialized'); 157 GetConfig.log('[GETX] $key has been initialized');
@@ -152,7 +179,10 @@ class GetInstance { @@ -152,7 +179,10 @@ class GetInstance {
152 // } 179 // }
153 // } 180 // }
154 181
155 - /// Find a instance from required class 182 + /// Finds a instance of the required Class<[S]> (or [tag])
  183 + /// In the case of using Get.[create], it will create an instance
  184 + /// each time you call [find]
  185 + ///
156 S find<S>({String tag}) { 186 S find<S>({String tag}) {
157 String key = _getKey(S, tag); 187 String key = _getKey(S, tag);
158 188
@@ -165,17 +195,17 @@ class GetInstance { @@ -165,17 +195,17 @@ class GetInstance {
165 throw "class ${S.toString()} with tag '$tag' is not register"; 195 throw "class ${S.toString()} with tag '$tag' is not register";
166 } 196 }
167 } 197 }
168 - initDependencies<S>(name: tag); 198 + _initDependencies<S>(name: tag);
169 199
170 return _singl[key].getDependency() as S; 200 return _singl[key].getDependency() as S;
171 } else { 201 } else {
172 if (!_factory.containsKey(key)) 202 if (!_factory.containsKey(key))
173 - throw " $S not found. You need call put<$S>($S()) before"; 203 + throw "$S not found. You need call put<$S>($S()) before";
174 204
175 GetConfig.log('[GETX] $S instance was created at that time'); 205 GetConfig.log('[GETX] $S instance was created at that time');
176 S _value = put<S>(_factory[key].builder() as S); 206 S _value = put<S>(_factory[key].builder() as S);
177 207
178 - initDependencies<S>(name: tag); 208 + _initDependencies<S>(name: tag);
179 209
180 if (GetConfig.smartManagement != SmartManagement.keepFactory && 210 if (GetConfig.smartManagement != SmartManagement.keepFactory &&
181 !_factory[key].fenix) { 211 !_factory[key].fenix) {
@@ -190,6 +220,12 @@ class GetInstance { @@ -190,6 +220,12 @@ class GetInstance {
190 return name == null ? type.toString() : type.toString() + name; 220 return name == null ? type.toString() : type.toString() + name;
191 } 221 }
192 222
  223 + /// Clears all registered instances (and/or tags).
  224 + /// Even the persistent ones.
  225 + ///
  226 + /// [clearFactory] clears the callbacks registered by [lazyPut]
  227 + /// [clearRouteBindings] clears Instances associated with routes.
  228 + ///
193 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) { 229 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) {
194 if (clearFactory) _factory.clear(); 230 if (clearFactory) _factory.clear();
195 if (clearRouteBindings) _routesKey.clear(); 231 if (clearRouteBindings) _routesKey.clear();
@@ -205,7 +241,8 @@ class GetInstance { @@ -205,7 +241,8 @@ class GetInstance {
205 // return s; 241 // return s;
206 // } 242 // }
207 243
208 - /// Delete class instance on [S] and clean memory 244 + /// Delete registered Class Instance [S] (or [tag]) and, closes any open
  245 + /// controllers [DisposableInterface], cleans up the memory
209 Future<bool> delete<S>({String tag, String key, bool force = false}) async { 246 Future<bool> delete<S>({String tag, String key, bool force = false}) async {
210 final newKey = key ?? _getKey(S, tag); 247 final newKey = key ?? _getKey(S, tag);
211 248
@@ -244,10 +281,10 @@ class GetInstance { @@ -244,10 +281,10 @@ class GetInstance {
244 }); 281 });
245 } 282 }
246 283
247 - /// check if instance is registered 284 + /// Check if a Class instance [S] (or [tag]) is registered.
248 bool isRegistered<S>({String tag}) => _singl.containsKey(_getKey(S, tag)); 285 bool isRegistered<S>({String tag}) => _singl.containsKey(_getKey(S, tag));
249 286
250 - /// check if instance is prepared 287 + /// Check if Class instance [S] (or [tag]) is prepared to be used.
251 bool isPrepared<S>({String tag}) => _factory.containsKey(_getKey(S, tag)); 288 bool isPrepared<S>({String tag}) => _factory.containsKey(_getKey(S, tag));
252 } 289 }
253 290
1 import 'dart:async'; 1 import 'dart:async';
  2 +
2 import 'package:flutter/scheduler.dart'; 3 import 'package:flutter/scheduler.dart';
3 import 'package:get/src/state_manager/rx/rx_callbacks.dart'; 4 import 'package:get/src/state_manager/rx/rx_callbacks.dart';
4 5
@@ -26,10 +27,30 @@ abstract class RxInterface<T> { @@ -26,10 +27,30 @@ abstract class RxInterface<T> {
26 /// once started, that service will remain in memory, such as Auth control for example. 27 /// once started, that service will remain in memory, such as Auth control for example.
27 abstract class GetxService extends DisposableInterface {} 28 abstract class GetxService extends DisposableInterface {}
28 29
  30 +/// Special callable class to keep the contract of a regular method, and avoid
  31 +/// overrides if you extend the class that uses it, as Dart has no final methods.
  32 +/// Used in [DisposableInterface] to avoid the danger of overriding onStart.
  33 +///
  34 +class _InternalFinalCallback<T> {
  35 + T Function() callback;
  36 + _InternalFinalCallback();
  37 + T call() => callback.call();
  38 +}
  39 +
29 abstract class DisposableInterface { 40 abstract class DisposableInterface {
30 - /// Called at the exact moment that the widget is allocated in memory.  
31 - /// Do not overwrite this method.  
32 - void onStart() { 41 + /// Called at the exact moment the widget is allocated in memory.
  42 + /// It uses an internal "callable" type, to avoid any @overrides in subclases.
  43 + /// This method should be internal and is required to define the lifetime cycle
  44 + /// of the subclass.
  45 + ///
  46 + final onStart = _InternalFinalCallback<void>();
  47 +
  48 + DisposableInterface() {
  49 + onStart.callback = _onStart;
  50 + }
  51 +
  52 + // Internal callback that starts the cycle of this controller.
  53 + void _onStart() {
33 onInit(); 54 onInit();
34 SchedulerBinding.instance?.addPostFrameCallback((_) => onReady()); 55 SchedulerBinding.instance?.addPostFrameCallback((_) => onReady());
35 } 56 }