fgyong
fgyong

Reputation: 81

how to Flutter Getx binds obs to Widget?

when I use Getx to update my Widget? I do not know Rx() how to contact to the thing I put in.

code is _obx=Rx(). but I send data is "".obs. that is not Rx() but this is RxString(). when I use "".obs.value="newString". why Rx() can know that who updates data.

just like :

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

class GetIncrementPage extends StatefulWidget {
  GetIncrementPage({Key key}) : super(key: key);

  @override
  _GetIncrementPageState createState() => _GetIncrementPageState();
}

class _GetIncrementPageState extends State<GetIncrementPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('get'),
      ),
      body: Container(
        alignment: Alignment.center,
        child: _body(),
      ),
    );
  }

  Widget _body() {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        OutlineButton(
          child: Text('get 数字加减'),
          onPressed: c.increment,
        ),
        OutlineButton(
          child: Text('get log 变化'),
          onPressed: c.change,
        ),

        Obx(() {
          printInfo(info: '刷新了页面 get_example');
          return Text(c.count.toString());
        }),

        ObxValue((v) {
          printInfo(info: '刷新了页面 get_ObxValue_log1 ');
          return Text('logValue:' + v.toString());
        }, ObjectKey('key').obs),

        Obx(() {
          printInfo(info: '刷新了页面 get_obx_log1');

          return Text('logObx:' + c.log.toString());
        }),
        Obx(() {
          printInfo(info: '刷新了页面 get_obx_log2');

          return Text(c.log2.toString());
        }),

        // ObxValue((var value) => Text('${value.toString()}'), c),
      ],
    );
  }

  @override
  void dispose() {
    Get.delete<Controller2>();
    super.dispose();
  }

  final Controller2 c = Get.put(Controller2());
}

///
/// Created by fgyong on 2020/10/22.
///

class Controller2 extends GetxController {
  var count = 0.obs;
  var count2 = 0.obs;

  final log = ''.obs;
  final log2 = ''.obs;

  increment() => count++;
  @override
  void onClose() {
    printInfo(info: 'Controller close');
    super.onClose();
  }

  void change() {
    log.value += ' ${log.value.length}';
  }
}

when i change log.value to new String,why log2 do not fresh.

class Obx extends StatefulWidget {
  final WidgetCallback builder;

  const Obx(this.builder);

  _ObxState createState() => _ObxState();
}

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

  _ObxState() {
    _observer = Rx();
  }

  @override
  void initState() {
    subs = _observer.subject.stream.listen((data) => setState(() {}));
    super.initState();
  }

  @override
  void dispose() {
    subs.cancel();
    _observer.close();
    super.dispose();
  }

  Widget get notifyChilds {
    final observer = getObs;
    getObs = _observer;
    final result = widget.builder();
    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.
      """;
    }
    getObs = observer;
    return result;
  }

  @override
  Widget build(BuildContext context) => notifyChilds;
}

Why can rx() establish contact with the log, please help me. When I update How can Rx() know when logging?

just help me.

Upvotes: 7

Views: 94253

Answers (3)

fgyong
fgyong

Reputation: 81

see link https://github.com/jonataslaw/getx/issues/937, when Obx() build,we named it ObxA, named "ABC".obs abcobs,

in Obx


  Widget get notifyChilds {
    final observer = getObs;
    getObs = _observer;
    final result = widget.builder();
    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.
      """;
    }
    getObs = observer;
    return result;
  }

when build,RxString() will execute get value,and addListen():

code is

  set value(T val) {
    if (_value == val && !firstRebuild) return;
    firstRebuild = false;
    _value = val;
    subject.add(_value);
  }

  /// Returns the current [value]
  T get value {
    if (getObs != null) {
      getObs.addListener(subject.stream);
    }
    return _value;
  }

void addListener(Stream<T> rxGetx) {
    if (_subscriptions.containsKey(rxGetx)) {
      return;
    }
    _subscriptions[rxGetx] = rxGetx.listen((data) {
      subject.add(data);
    });
  }

so They made a connection

Upvotes: 1

Baker
Baker

Reputation: 28010

You can use Obx or GetX widgets from Get to "listen" to changes to observable variables you declare in a GetxController.

I think you are also confusing Rx as an ObserVER vs. ObservABLE. Rx is an observable, i.e. you watch it for changes using Obx or GetX widgets, (I guess you can call these two widgets "Observers".)

Basic Example

class Log2Page extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Controller c = Get.put(Controller());
    // ↑ declare controller inside build method

    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Obx(
                      () => Text('${c.log2.value}')
              ),
              RaisedButton(
                child: Text('Add +1'),
                onPressed: c.change,
              )
            ],
          ),
        ),
      ),
    );
  }
}

class Controller extends GetxController {
  RxInt log2 = 0.obs;

  void change() => log2.value++;
}
  1. You likely don't need a StatefulWidget when using GetX. A GetxController lives outside the lifecycle of widgets. State is stored in a GetX Controller (instead of in a StatefulWidget).
  2. GetX takes care of streams & subscriptions through variables you declare as obs, like count.obs and log2.obs. When you want to "listen" or "observe", use Obx or GetX widgets. These automatically listen to obs changes of its child and rebuild when it changes.

Obx vs. GetBuilder vs. GetX

class Log2Page extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Controller c = Get.put(Controller());

    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Obx(
                      () => Text('Obx: ${c.log2.value}')
              ),
              // ↓ requires manual controller.update() call
              GetBuilder<Controller>(
                builder: (_c) => Text('GetBuilder: ${_c.log2.value}'),
              ),
              // ↓ controller instantiated by Get widget
              GetX<Controller>(
                init: Controller(),
                builder: (_c) => Text('GetX: ${_c.log2.value}'),
              ),
              RaisedButton(
                child: Text('Add +1'),
                onPressed: c.change,
              ),
              RaisedButton(
                child: Text('Update GetBuilder'),
                onPressed: c.update, // rebuild GetBuilder widget
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class Controller extends GetxController {
  RxInt log2 = 0.obs;

  void change() => log2.value++;
}

Obx

Listens to observable (obs) changes. Controller needs to already be declared/initialized elsewhere to use.

GetX

Listens to observable (obs) changes. Can initialize controller itself using init: constructor argument, if not done elsewhere. Optional argument. Safe to use init: if Controller already instantiated. Will connect to existing instance.

GetBuilder

Does not listen to obs changes. Must be rebuilt manually by you, calling controller.update(). Similar to a setState() call. Can initialize controller itself using init: argument, if not done elsewhere. Optional.

Upvotes: 44

Katekko
Katekko

Reputation: 375

First:

when I "".obx.value="newString".why Rx() can know.

This is wrong, the .obx doesn't exist, I guess you mean .obs;

When you create a OBS variable like: final a = ''.obs, the type of this var will be a RxString(), so you can use to observer this var whatever you want to.

I know two widgets can you use to observer in your screen:

GetX(), Obx()

Upvotes: 0

Related Questions