Jonny Borges
Committed by GitHub

Merge pull request #535 from Nipodemos/add-BindingsBuilder-docs

[docs] BindingBuilder documentation, refactor in dependency management docs
1 -- [Simple Instance Manager](#simple-instance-manager)  
2 -- [Options](#options)  
3 -- [Bindings](#bindings) 1 +# Dependency Management
  2 +- [Dependency Management](#dependency-management)
  3 + - [Usage](#usage)
  4 + - [Instancing methods](#instancing-methods)
  5 + - [Get.put()](#getput)
  6 + - [Get.lazyPut](#getlazyput)
  7 + - [Get.putAsync](#getputasync)
  8 + - [Get.create](#getcreate)
  9 + - [Differences between methods:](#differences-between-methods)
  10 + - [Bindings](#bindings)
4 - [How to use](#how-to-use) 11 - [How to use](#how-to-use)
5 -- [SmartManagement](#smartmanagement)  
6 -  
7 -## Simple Instance Manager 12 + - [BindingsBuilder](#bindingsbuilder)
  13 + - [SmartManagement](#smartmanagement)
  14 + - [SmartManagement.full](#smartmanagementfull)
  15 + - [SmartManagement.onlyBuilders](#smartmanagementonlybuilders)
  16 + - [SmartManagement.keepFactory](#smartmanagementkeepfactory)
  17 + - [How bindings work under the hood](#how-bindings-work-under-the-hood)
  18 + - [Notes](#notes)
8 19
9 Get has a simple and powerful dependency manager that allows you to retrieve the same class as your Bloc or Controller with just 1 lines of code, no Provider context, no inheritedWidget: 20 Get has a simple and powerful dependency manager that allows you to retrieve the same class as your Bloc or Controller with just 1 lines of code, no Provider context, no inheritedWidget:
10 21
@@ -12,21 +23,13 @@ Get has a simple and powerful dependency manager that allows you to retrieve the @@ -12,21 +23,13 @@ Get has a simple and powerful dependency manager that allows you to retrieve the
12 Controller controller = Get.put(Controller()); // Rather Controller controller = Controller(); 23 Controller controller = Get.put(Controller()); // Rather Controller controller = Controller();
13 ``` 24 ```
14 25
15 -- Note: If you are using Get's State Manager, pay more attention to the bindings api, which will make easier to connect your view to your controller.  
16 -  
17 Instead of instantiating your class within the class you are using, you are instantiating it within the Get instance, which will make it available throughout your App. 26 Instead of instantiating your class within the class you are using, you are instantiating it within the Get instance, which will make it available throughout your App.
18 So you can use your controller (or Bloc class) normally 27 So you can use your controller (or Bloc class) normally
19 28
20 -**Tip:** Get dependency management is decloupled from other parts of the package, so if for example your app is already using a state manager (any one, it doesn't matter), you don't need to rewrite it all, you can use this dependency injection with no problems at all  
21 -  
22 -```dart  
23 -controller.fetchApi();  
24 -```  
25 -  
26 Imagine that you have navigated through numerous routes, and you need a data that was left behind in your controller, you would need a state manager combined with the Provider or Get_it, correct? Not with Get. You just need to ask Get to "find" for your controller, you don't need any additional dependencies: 29 Imagine that you have navigated through numerous routes, and you need a data that was left behind in your controller, you would need a state manager combined with the Provider or Get_it, correct? Not with Get. You just need to ask Get to "find" for your controller, you don't need any additional dependencies:
27 30
28 ```dart 31 ```dart
29 -Controller controller = Get.find(); 32 +Controller controller = Get.find(); // or final controller = Get.find<Controlelr>();
30 //Yes, it looks like Magic, Get will find your controller, and will deliver it to you. You can have 1 million controllers instantiated, Get will always give you the right controller. 33 //Yes, it looks like Magic, Get will find your controller, and will deliver it to you. You can have 1 million controllers instantiated, Get will always give you the right controller.
31 ``` 34 ```
32 35
@@ -36,14 +39,14 @@ And then you will be able to recover your controller data that was obtained back @@ -36,14 +39,14 @@ And then you will be able to recover your controller data that was obtained back
36 Text(controller.textFromApi); 39 Text(controller.textFromApi);
37 ``` 40 ```
38 41
39 -Looking for lazy loading? You can declare all your controllers, and it will be called only when someone needs it. You can do this with: 42 +It is possible to lazyLoad a dependency so that it will be instantiated only when is used. Very useful for computational expensive classes or when you know you will not gonna use that class at that time.
40 43
41 ```dart 44 ```dart
42 -Get.lazyPut<Service>(()=> ApiMock());  
43 -/// ApiMock will only be called when someone uses Get.find<Service> for the first time 45 +Get.lazyPut<ApiMock>(() => ApiMock());
  46 +/// ApiMock will only be called when someone uses Get.find<ApiMock> for the first time
44 ``` 47 ```
45 48
46 -If you want to register an asynchronous instance, you can use Get.putAsync. 49 +If you want to register an asynchronous instance, you can use `Get.putAsync`:
47 50
48 ```dart 51 ```dart
49 Get.putAsync<SharedPreferences>(() async { 52 Get.putAsync<SharedPreferences>(() async {
@@ -53,7 +56,10 @@ Get.putAsync<SharedPreferences>(() async { @@ -53,7 +56,10 @@ Get.putAsync<SharedPreferences>(() async {
53 }); 56 });
54 ``` 57 ```
55 58
56 -usage: 59 +- Note: If you are using Get's State Manager, pay more attention to the [Bindings](#bindings) api, which will make easier to connect your view to your controller.
  60 +- Note²: Get dependency management is decloupled from other parts of the package, so if for example your app is already using a state manager (any one, it doesn't matter), you don't need to change that, you can use this dependency injection manager with no problems at all
  61 +
  62 +## Usage
57 63
58 ```dart 64 ```dart
59 int count = Get.find<SharedPreferences>().getInt('counter'); 65 int count = Get.find<SharedPreferences>().getInt('counter');
@@ -70,12 +76,14 @@ Get.delete<Controller>(); @@ -70,12 +76,14 @@ Get.delete<Controller>();
70 76
71 Although Getx already delivers very good settings for use, it is possible to refine them even more so that it become more useful to the programmer. The methods and it's configurable parameters are: 77 Although Getx already delivers very good settings for use, it is possible to refine them even more so that it become more useful to the programmer. The methods and it's configurable parameters are:
72 78
73 -- Get.put(): 79 +### Get.put()
  80 +
  81 +The most common way of inserting a dependency. Good for the controllers of your views for example.
74 82
75 ```dart 83 ```dart
76 Get.put<S>( 84 Get.put<S>(
77 // mandatory: the class that you want to get to save, like a controller or anything 85 // mandatory: the class that you want to get to save, like a controller or anything
78 - // note: that "S" means that it can be anything 86 + // note: "S" means that it can be a class of any type
79 S dependency 87 S dependency
80 88
81 // optional: this is for when you want multiple classess that are of the same type 89 // optional: this is for when you want multiple classess that are of the same type
@@ -96,16 +104,22 @@ Get.put<S>( @@ -96,16 +104,22 @@ Get.put<S>(
96 bool overrideAbstract = false, 104 bool overrideAbstract = false,
97 105
98 // optional: allows you to create the dependency using function instead of the dependency itself. 106 // optional: allows you to create the dependency using function instead of the dependency itself.
  107 + // this one is not commonly used
99 InstanceBuilderCallback<S> builder, 108 InstanceBuilderCallback<S> builder,
100 ) 109 )
  110 +
  111 +// Example:
  112 +
  113 +Get.put<LoginController>(LoginController(), permanent: true)
101 ``` 114 ```
102 115
103 -- Get.lazyPut: 116 +### Get.lazyPut
  117 +
  118 +With lazyPut, the dependency will be only instantiated when it's called. This is particularly useful if you want to instantiate several classes in just one place, but don't need that instances immediatly
104 119
105 ```dart 120 ```dart
106 Get.lazyPut<S>( 121 Get.lazyPut<S>(
107 // mandatory: a method that will be executed when your class is called for the first time 122 // mandatory: a method that will be executed when your class is called for the first time
108 - // Example: Get.lazyPut<Controller>( () => Controller() )  
109 InstanceBuilderCallback builder, 123 InstanceBuilderCallback builder,
110 124
111 // optional: same as Get.put(), it is used for when you want multiple different instance of a same class 125 // optional: same as Get.put(), it is used for when you want multiple different instance of a same class
@@ -119,15 +133,29 @@ Get.lazyPut<S>( @@ -119,15 +133,29 @@ Get.lazyPut<S>(
119 bool fenix = false 133 bool fenix = false
120 134
121 ) 135 )
  136 +
  137 +// example
  138 +Get.lazyPut<FirebaseAuth>(
  139 + () => {
  140 + // ... some logic if needed
  141 + return FirebaseAuth()
  142 + },
  143 + tag: Math.random().toString(),
  144 + fenix: true
  145 +)
  146 +
  147 +// example 2:
  148 +Get.lazyPut<Controller>( () => Controller() )
122 ``` 149 ```
123 150
124 -- Get.putAsync: 151 +### Get.putAsync
  152 +
  153 +Since `Get.put()` does not support async methods/classes, you need to use Get.putAsync. The way of declare is equal to Get.lazyPut
125 154
126 ```dart 155 ```dart
127 Get.putAsync<S>( 156 Get.putAsync<S>(
128 157
129 // mandatory: an async method that will be executed to instantiate your class 158 // mandatory: an async method that will be executed to instantiate your class
130 - // Example: Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )  
131 AsyncInstanceBuilderCallback<S> builder, 159 AsyncInstanceBuilderCallback<S> builder,
132 160
133 // optional: same as Get.put(), it is used for when you want multiple different instance of a same class 161 // optional: same as Get.put(), it is used for when you want multiple different instance of a same class
@@ -137,9 +165,15 @@ Get.putAsync<S>( @@ -137,9 +165,15 @@ Get.putAsync<S>(
137 // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app 165 // optional: same as in Get.put(), used when you need to maintain that instance alive in the entire app
138 // defaults to false 166 // defaults to false
139 bool permanent = false 167 bool permanent = false
  168 +)
  169 +
  170 +// Example
  171 +Get.putAsync<YourAsyncClass>( () async => await YourAsyncClass() )
140 ``` 172 ```
141 173
142 -- Get.create: 174 +### Get.create
  175 +
  176 +This one is tricky. A detailed explanation of what this is and the differences between the other one can be found on [Differences between methods:](#differences-between-methods) section
143 177
144 ```dart 178 ```dart
145 Get.create<S>( 179 Get.create<S>(
@@ -160,19 +194,19 @@ Get.create<S>( @@ -160,19 +194,19 @@ Get.create<S>(
160 bool permanent = true 194 bool permanent = true
161 ``` 195 ```
162 196
163 -### Diferences between methods: 197 +## Differences between methods
164 198
165 First, let's of the `fenix` of Get.lazyPut and the `permanent` of the other methods. 199 First, let's of the `fenix` of Get.lazyPut and the `permanent` of the other methods.
166 200
167 The fundamental difference between `permanent` and `fenix` is how you want to store your instances. 201 The fundamental difference between `permanent` and `fenix` is how you want to store your instances.
168 Reinforcing: by default, GetX deletes instances when they are not is use. 202 Reinforcing: by default, GetX deletes instances when they are not is use.
169 It means that: If screen 1 has controller 1 and screen 2 has controller 2 and you remove the first route from stack, (like if you use `Get.off()` or `Get.offName()`) the controller 1 lost it's use so it will be erased. 203 It means that: If screen 1 has controller 1 and screen 2 has controller 2 and you remove the first route from stack, (like if you use `Get.off()` or `Get.offName()`) the controller 1 lost it's use so it will be erased.
170 -But if you want to opt to `permanent:true`, then the controller will not be lost in this transition - which is very usefult for services that you want to keep alive thoughout the entire application.  
171 -`fenix` in the other hand is for services that you don't worry in losing between screen changes, but when you need that service, you expect that it is alive. So basically, it will dispose the unused controller/service/class, but when you need that, it will "recreate from the ashes" a new instance. 204 +But if you want to opt for using `permanent:true`, then the controller will not be lost in this transition - which is very useful for services that you want to keep alive throughout the entire application.
  205 +`fenix` in the other hand is for services that you don't worry in losing between screen changes, but when you need that service, you expect that it is alive. So basically, it will dispose the unused controller/service/class, but when you need it, it will "recreate from the ashes" a new instance.
172 206
173 Proceeding with the differences between methods: 207 Proceeding with the differences between methods:
174 208
175 -- Get.put and Get.putAsync follow the same creation order, with the difference that asyn opt for applying a asynchronous method: those two methods create and initialize the instance. That one is inserted directly in the memory, using the internal method `insert` with the parameters `permanent: false` and `isSingleton: true` (this isSingleton parameter only porpuse is to tell if it is to use the dependency on `dependency` or if it is to use the dependency on `FcBuilderFunc`). After that, `Get.find()` is called that immediately initialize the instances that are on memory. 209 +- Get.put and Get.putAsync follow the same creation order, with the difference that the second uses an asynchronous method: those two methods create and initialize the instance. That one is inserted directly in the memory, using the internal method `insert` with the parameters `permanent: false` and `isSingleton: true` (this isSingleton parameter only porpuse is to tell if it is to use the dependency on `dependency` or if it is to use the dependency on `FcBuilderFunc`). After that, `Get.find()` is called that immediately initialize the instances that are on memory.
176 210
177 - Get.create: As the name implies, it will "create" your dependency! Similar to `Get.put()`, it also call the internal method `insert` to instancing. But `permanent` became true and `isSingleton` became false (since we are "creating" our dependency, there is no way for it to be a singleton instace, that's why is false). And because it has `permanent: true`, we have by default the benefit of not losing it between screens! Also, `Get.find()` is not called immediately, it wait to be used in the screen to be called. It is created this way to make use of the parameter `permanent`, since then, worth noticing, `Get.create()` was made with the goal of create not shared instances, but don't get disposed, like for example a button in a listView, that you want a unique instance for that list - because of that, Get.create must be used together with GetWidget. 211 - Get.create: As the name implies, it will "create" your dependency! Similar to `Get.put()`, it also call the internal method `insert` to instancing. But `permanent` became true and `isSingleton` became false (since we are "creating" our dependency, there is no way for it to be a singleton instace, that's why is false). And because it has `permanent: true`, we have by default the benefit of not losing it between screens! Also, `Get.find()` is not called immediately, it wait to be used in the screen to be called. It is created this way to make use of the parameter `permanent`, since then, worth noticing, `Get.create()` was made with the goal of create not shared instances, but don't get disposed, like for example a button in a listView, that you want a unique instance for that list - because of that, Get.create must be used together with GetWidget.
178 212
@@ -193,19 +227,24 @@ In addition, the Binding class will allow you to have SmartManager configuration @@ -193,19 +227,24 @@ In addition, the Binding class will allow you to have SmartManager configuration
193 - Create a class and implements Binding 227 - Create a class and implements Binding
194 228
195 ```dart 229 ```dart
196 -class HomeBinding implements Bindings {  
197 -  
198 -} 230 +class HomeBinding implements Bindings {}
199 ``` 231 ```
200 232
201 Your IDE will automatically ask you to override the "dependencies" method, and you just need to click on the lamp, override the method, and insert all the classes you are going to use on that route: 233 Your IDE will automatically ask you to override the "dependencies" method, and you just need to click on the lamp, override the method, and insert all the classes you are going to use on that route:
202 234
203 ```dart 235 ```dart
204 -class HomeBinding implements Bindings{ 236 +class HomeBinding implements Bindings {
205 @override 237 @override
206 void dependencies() { 238 void dependencies() {
207 - Get.lazyPut<ControllerX>(() => ControllerX());  
208 - Get.lazyPut<Service>(()=> Api()); 239 + Get.lazyPut<HomeController>(() => HomeController());
  240 + Get.put<Service>(()=> Api());
  241 + }
  242 +}
  243 +
  244 +class DetailsBinding implements Bindings {
  245 + @override
  246 + void dependencies() {
  247 + Get.lazyPut<DetailsController>(() => DetailsController());
209 } 248 }
210 } 249 }
211 ``` 250 ```
@@ -216,14 +255,24 @@ Now you just need to inform your route, that you will use that binding to make t @@ -216,14 +255,24 @@ Now you just need to inform your route, that you will use that binding to make t
216 255
217 ```dart 256 ```dart
218 getPages: [ 257 getPages: [
219 - GetPage(name: '/', page: () => Home(), binding: HomeBinding()),  
220 -] 258 + GetPage(
  259 + name: '/',
  260 + page: () => HomeView(),
  261 + binding: HomeBinding(),
  262 + ),
  263 + GetPage(
  264 + name: '/details',
  265 + page: () => DetailsView(),
  266 + binding: DetailsBinding(),
  267 + ),
  268 +];
221 ``` 269 ```
222 270
223 - Using normal routes: 271 - Using normal routes:
224 272
225 ```dart 273 ```dart
226 Get.to(Home(), binding: HomeBinding()); 274 Get.to(Home(), binding: HomeBinding());
  275 +Get.to(DetailsView(), binding: DetailsBinding())
227 ``` 276 ```
228 277
229 There, you don't have to worry about memory management of your application anymore, Get will do it for you. 278 There, you don't have to worry about memory management of your application anymore, Get will do it for you.
@@ -237,17 +286,69 @@ GetMaterialApp( @@ -237,17 +286,69 @@ GetMaterialApp(
237 ); 286 );
238 ``` 287 ```
239 288
240 -## SmartManagement 289 +### BindingsBuilder
  290 +
  291 +The default way of creating a binding creating a class that implements Bindings.
  292 +But alternatively, you can use `BindingsBuilder` callback so that you can simply use a function to instantiate whatever you desire.
  293 +
  294 +Example:
  295 +
  296 +```dart
  297 +getPages: [
  298 + GetPage(
  299 + name: '/',
  300 + page: () => HomeView(),
  301 + binding: BindingsBuilder(() => {
  302 + Get.lazyPut<ControllerX>(() => ControllerX());
  303 + Get.put<Service>(()=> Api());
  304 + }),
  305 + ),
  306 + GetPage(
  307 + name: '/details',
  308 + page: () => DetailsView(),
  309 + binding: BindingsBuilder(() => {
  310 + Get.lazyPut<DetailsController>(() => DetailsController());
  311 + }),
  312 + ),
  313 +];
  314 +```
  315 +
  316 +That way you can avoid to create one Binding class for each route making this even simpler.
  317 +
  318 +Both ways of doing work perfectly fine and we want you to use what most suit your tastes.
  319 +
  320 +### SmartManagement
  321 +
  322 +GetX by default disposes unused controllers from memory, even if a failure occurs and a widget that uses it is not properly disposed.
  323 +This is what is called the `full` mode of dependency management.
  324 +But if you want to change the way GetX controls the disposal of classes, you have `SmartManagement` class that you can set different behaviors.
  325 +
  326 +#### SmartManagement.full
  327 +
  328 +It is the default one. Dispose classes that are not being used and were not set to be permanent. In the majority of the cases you will want to keep this config untouched. If you new to GetX then don't change this.
  329 +
  330 +#### SmartManagement.onlyBuilders
  331 +With this option, only controllers started in `init:` or loaded into a Binding with `Get.lazyPut` will be disposed.
  332 +
  333 +If you use `Get.put()` or `Get.putAsync()` or any other approach, SmartManagement will not have permissions to exclude this dependency.
241 334
242 -Always prefer to use standard SmartManagement (full), you do not need to configure anything for that, Get already gives it to you by default. It will surely eliminate all your disused controllers from memory, as its refined control removes the dependency, even if a failure occurs and a widget that uses it is not properly disposed.  
243 -The "full" mode is also safe enough to be used with StatelessWidget, as it has numerous security callbacks that will prevent a controller from remaining in memory if it is not being used by any widget, and disposition is not important here. However, if you are bothered by the default behavior, or just don't want it to happen, Get offers other, more lenient options for intelligent memory management, such as SmartManagement.onlyBuilders, which will depend on the effective removal of widgets using the controller. tree to remove it, and you can prevent a controller from being deployed using "autoRemove: false" in your GetBuilder/GetX.  
244 -With this option, only controllers started in "init:" or loaded into a Binding with "Get.lazyPut" will be disposed, if you use Get.put or any other approach, SmartManagement will not have permissions to exclude this dependency.  
245 With the default behavior, even widgets instantiated with "Get.put" will be removed, unlike SmartManagement.onlyBuilders. 335 With the default behavior, even widgets instantiated with "Get.put" will be removed, unlike SmartManagement.onlyBuilders.
246 -SmartManagement.keepFactory is like SmartManagement.full, with one difference. SmartManagement.full purges the factories from the premises, so that Get.lazyPut() will only be able to be called once and your factory and references will be self-destructing. SmartManagement.keepFactory will remove its dependencies when necessary, however, it will keep the "shape" of these, to make an equal one if you need an instance of that again.  
247 -Instead of using SmartManagement.keepFactory you can use Bindings.  
248 -Bindings creates transitory factories, which are created the moment you click to go to another screen, and will be destroyed as soon as the screen-changing animation happens. It is so little time that the analyzer will not even be able to register it. When you navigate to this screen again, a new temporary factory will be called, so this is preferable to using SmartManagement.keepFactory, but if you don't want to create Bindings, or want to keep all your dependencies on the same Binding, it will certainly help you . Factories take up little memory, they don't hold instances, but a function with the "shape" of that class you want. This is very little, but since the purpose of this lib is to get the maximum performance possible using the minimum resources, Get removes even the factories by default. Use whichever is most convenient for you.  
249 336
250 -- NOTE: DO NOT USE SmartManagement.keepFactory if you are using multiple Bindings. It was designed to be used without Bindings, or with a single Binding linked in the GetMaterialApp's initialBinding. 337 +#### SmartManagement.keepFactory
  338 +
  339 +Just like SmartManagement.full, it will remove it's dependencies when it's not being used anymore. However, it will keep the their factory, which means it will recreate the dependency if you need that instance again.
  340 +
  341 +### How bindings work under the hood
  342 +Bindings creates transitory factories, which are created the moment you click to go to another screen, and will be destroyed as soon as the screen-changing animation happens.
  343 +This happens so fast that the analyzer will not even be able to register it.
  344 +When you navigate to this screen again, a new temporary factory will be called, so this is preferable to using SmartManagement.keepFactory, but if you don't want to create Bindings, or want to keep all your dependencies on the same Binding, it will certainly help you.
  345 +Factories take up little memory, they don't hold instances, but a function with the "shape" of that class you want.
  346 +This has a very low cost in memory, but since the purpose of this lib is to get the maximum performance possible using the minimum resources, Get removes even the factories by default.
  347 +Use whichever is most convenient for you.
  348 +
  349 +## Notes
  350 +
  351 +- DO NOT USE SmartManagement.keepFactory if you are using multiple Bindings. It was designed to be used without Bindings, or with a single Binding linked in the GetMaterialApp's initialBinding.
251 352
252 -- NOTE2: Using Bindings is completely optional, you can use Get.put() and Get.find() on classes that use a given controller without any problem.  
253 -However, if you work with Services or any other abstraction, I recommend using Bindings for a larger organization. 353 +- Using Bindings is completely optional, if you want you can use `Get.put()` and `Get.find()` on classes that use a given controller without any problem.
  354 +However, if you work with Services or any other abstraction, I recommend using Bindings for a better organization.
1 -sdk.dir=/home/jonny/Android/Sdk  
2 -flutter.sdk=/opt/flutter  
3 -flutter.buildMode=debug  
4 -flutter.versionName=1.0.0  
5 -flutter.versionCode=1