From the original: www.jianshu.com/p/567dbad52…

Getx profile

The official website has a full set of Chinese documents.

See: github.com/jonataslaw/…

The source code

Getx provides very rich functionality, function modules:

├ ─ ─ lib │ ├ ─ ─ get_connect [network module] │ │ ├ ─ ─ HTTP │ │ └ ─ ─ sockets │ ├ ─ ─ get_core [core modules] │ ├ ─ ─ get_instance [dependency management module] │ ├ ─ ─ Get_navigation routing management module] [│ ├ ─ ─ get_rx [response type module (similar to RxDart)] │ ├ ─ ─ get_state_manager [state management module] │ └ ─ ─ get_utils universal tool [] │ ├ ─ ─ │ ├─ ├─ Platform │ ├─ The extensions │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ ├─ Platform │ └─ garbage [class]Copy the code

Setup

  1. Add the dependency get: ^3.24.0 to the pubspec.yaml file
  2. MaterialApp GetMaterialApp instead

See the complete code below, which implements the function of HelloWorld:

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() => runApp(GetMaterialApp(home: Home()));

/// Counter controller
class CounterController extends GetxController {
  var count = 0.obs;
}

class Home extends StatelessWidget {
  // Initialize the counter controller, place it in dependency management, and get the instance
  final _counter = Get.put(CounterController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Count Getx')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('You have pushed the button this many times:'),
            Obx(() => Text(// Respond to data changes
                  '${_counter.count.value}',
                  style: Theme.of(context).textTheme.headline4,
                )),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        // Trigger data changes
        onPressed: () => _counter.count + 1,
        tooltip: 'Increment', child: Icon(Icons.add), ), ); }}Copy the code
  1. The code analysis
  • CounterController class
    1. Inherited from GetxController
    2. Declare a reactive variable count of type RxInt, defined in the get_rx module.
  • Home class
    1. The _counter variable initializes the counter controller, puts it into dependency management, and gets the instance
    2. The corresponding response data changes use the Widget corresponding to Rx type: Obx. An Obx update is triggered when the value of CounterController.count changes. When calling in Obx _counter. Count. The value, RxInterface. Proxy. The addListener () for the value added to monitor events

How do Getx route management, state management and dependency management work together

1. How is status management data stored?

final _counter = Get.put(CounterController());
Copy the code

See the following figure for the call process:

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);
  }
Copy the code

In the call stack, you can see that the final CounterController data is stored in the GetInstance global singleton. In contrast to provider state management, provider data is stored in the InheritedWidget, and only child nodes can obtain the stored data. When the data is irrelevant to the interface, the data in the provider cannot be obtained. Getx, by contrast, stores data in singletons and does not rely on the UI, which is more flexible and more widely tried.

2. How can state management be managed automatically?

See figure below:

  1. Add the binding between GetxController and route

  // Save the mapping between the route and GetxController
  static final Map<String.String> _routesKey = {}; .// Match the class name of the CounterController to the current route and store it in _routesKey.
  void _registerRouteInstance<S>({String tag}) {
    _routesKey.putIfAbsent(_getKey(S, tag), () => Get.reference);
  }
Copy the code
  1. When the page exits, GetPageroute. dispose removes the Key and Value in the _routesKey and removes the GetxController class saved in getInstance. _singl

Note: The timing of the Get. Put call, like Home in the previous example, does not bind the path correctly. Get. Put is triggered before the Home page is entered, and the path to Get. Reference is the previous routing path of Home.

3. How does Obx() respond to changes in Obs variables?

Obx(() => Text(// Respond to data changes
                  '${_counter.count.value}',
                  style: Theme.of(context).textTheme.headline4,
                )),
Copy the code

All you can see is that _counter.count. Value gets the value, which is where the data response relationship is bound. Look at the source code implementation:

  T get value {
    if(RxInterface.proxy ! =null) {
      RxInterface.proxy.addListener(subject); // Set up the data relationship and add the data change monitor
    }
    return _value;
  }
Copy the code

Subject is of type GetStream. Data change monitor figure out, then look at how Obx is listening to data change, look at Obx source code:

class Obx extends ObxWidget {
  final WidgetCallback builder;

  const Obx(this.builder);

  @override
  Widget build() => builder();
}
Copy the code

Obx inherits from ObxWidget.

abstract class ObxWidget extends StatefulWidget {
  const ObxWidget({Key key}) : super(key: key);

  @override
  _ObxState createState() => _ObxState();

  @protected
  Widget build();
}

class _ObxState extends State<ObxWidget> {
  RxInterface _observer;
  StreamSubscription subs;

  _ObxState() {
    _observer = RxNotifier();
  }

  @override
  void initState() {
    subs = _observer.listen(_updateTree);
    super.initState();
  }

  Widget get notifyChilds {
    final observer = RxInterface.proxy;
    RxInterface.proxy = _observer;
    final result = widget.build();
    if(! _observer.canUpdate) {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;
  }

  @override
  Widget build(BuildContext context) => notifyChilds;
}
Copy the code
  1. In initState(), subs = _observer.listen(_updateTree), which listens for data updates, calls _updateTree to update the view when the data is updated.
  2. Rxinterface.proxy = _observer in notifyChilds(); Return to the code beginning with Obx() :
  Obx(() => Text(// Respond to data changes
                  '${_counter.count.value}',
                  style: Theme.of(context).textTheme.headline4,
                )),

  T get value {
    if(RxInterface.proxy ! =null) {
      RxInterface.proxy.addListener(subject); // Set up the data relationship and add the data change monitor
    }
    return _value;
  }
Copy the code

You can see rxinterface.proxy. NotifyChilds () is called when Obx executes build, assigns the current _observer value to rxinterface.proxy, executes widget.build(), and runs to the get method of _counter.count.value. RxInterface.proxy.addListener(subject); The association between the variable and the Widget is now complete.

  1. Restore rxinterface.proxy as shown in the following code:
    final result = widget.build();
    if(! _observer.canUpdate) {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;
Copy the code

RxInterface.proxy = observer; Restore rxinterface. proxy to the previously saved value.

4. GetBuilder

This binding is easier to understand, so I won’t write it

The above code for their own understanding, there are mistakes welcome to point out.