简体   繁体   English

在小部件之外使用 GetX 观察列表

[英]Observe List with GetX outside of widget

I have isolate that makes some heavy calculations then on receive the list with the result run a for loop to add them to observable list with items var items = [].obs;我隔离了一些繁重的计算,然后在接收列表时运行一个 for 循环,将它们添加到带有 items var items = [].obs; 的可观察列表中

The thing is I'm trying to observe the items list from a splash controller and once the list,= [] I'll navigate to another screen: so in onInit() I have this code:问题是我试图从启动 controller 观察项目列表,一旦列表,= [] 我将导航到另一个屏幕:所以在 onInit() 我有这个代码:

class SplashController extends GetxController {
  @override
  void onInit() {
    final ItemsController _itemsController = Get.put(ItemsController());

    // TODO: implement onInit
    super.onInit();
    ever(_itemsController.items, (newItems) {
      print('new items here $newItems');
    });
  }
}

Despite the itemsController.items is populated (after the for loop I print the itemsController.items and it's not empty) the worker on the splash controller doesn't trigger when the items are added.尽管 itemsController.items 已填充(在 for 循环之后我打印 itemsController.items 并且它不是空的),但在添加项目时,启动 controller 上的工作人员不会触发。

What am I doing wrong here?我在这里做错了什么? Is this the correct way to observe variable outside of widget using Getx?这是使用 Getx 观察小部件外部变量的正确方法吗? Can anyone help me with this, please?有人可以帮我解决这个问题吗?

Edit: In the items controller I'm adding the items this way编辑:在项目 controller 我以这种方式添加项目

add(item) => items.add(item)

Continuing with the Isolate example , but without using a StatefulWidget ie no setState usage.继续Isolate 示例,但不使用 StatefulWidget,即不使用 setState。

The ever worker in SplashX will receive items generated from the Isolate. SplashX 中的ever worker 将收到从 Isolate 生成的物品。 The Stateless Widget page will display the latest item emitted from the Isolate. Stateless Widget 页面将显示从 Isolate 发出的最新项目。

SplashController + ever worker SplashController + ever工作者

class SplashX extends GetxController {
  ItemsX itemsX;

  SplashX({this.itemsX});

  @override
  void onInit() {
    super.onInit();

    ever(itemsX.items, (items) => print('Ever items: $items'));
  }
}

Items Controller项目 Controller

class ItemsX extends GetxController {
  RxList<String> items = RxList<String>();
  bool running = false;

  void add(String item) {
    items.add(item);
  }

  void updateStatus(bool isRunning) {
    running = isRunning;
    update();
  }

  void reset() {
    items.clear();
  }

  /// Only relevant for UnusedControllerPage
  List<Widget> get texts => items.map((item) => Text('$item')).toList();
}

Isolate Controller隔离 Controller

class IsolateX extends GetxController {
  IsolateX({this.itemsX});

  ItemsX itemsX;
  Isolate _isolate;
  static int _counter = 0;
  ReceivePort _receivePort;
  bool running = false;

  static void _checkTimer(SendPort sendPort) async {
    Timer.periodic(Duration(seconds: 1), (Timer t) {
      _counter++;
      String msg = 'notification ' + _counter.toString();
      print('SEND: ' + msg);
      sendPort.send(msg);
    });
  }

  void _handleMessage(dynamic data) {
    itemsX.add(data); // update observable
  }

  void updateStatus(bool isRunning) {
    running = isRunning;
    update();
  }

  void start() async {
    itemsX.reset();
    updateStatus(true);
    _receivePort = ReceivePort();
    _isolate = await Isolate.spawn(_checkTimer, _receivePort.sendPort);
    _receivePort.listen(_handleMessage, onDone:() {
      print("done!");
    });
  }

  void stop() {
    if (_isolate != null) {
      updateStatus(false);
      _receivePort.close();
      _isolate.kill(priority: Isolate.immediate);
      _isolate = null;
    }
  }
}

Stateless Page无状态页面

class MyHomePageStateless extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ItemsX ix = Get.put(ItemsX()); // Instantiate ItemsController
    IsolateX isox = Get.put(IsolateX(itemsX: ix));
    SplashX sx = Get.put(SplashX(itemsX: ix));

    return Scaffold(
      appBar: AppBar(
        title: Text('Isolate Stateless'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            GetX<ItemsX>(
              builder: (ix) => Text(ix.items.isNotEmpty ? ix.items.last : ''),
            ),
          ],
        ),
      ),
      floatingActionButton: GetBuilder<IsolateX>(
        builder: (_ix) => FloatingActionButton(
          onPressed: _ix.running ? isox.stop : isox.start,
          tooltip: _ix.running ? 'Timer stop' : 'Timer start',
          child: _ix.running ? Icon(Icons.stop) : Icon(Icons.play_arrow),
        ),
      ),
    );
  }
}

Here's two controllers, with one ever worker listening for events of another controller, where that controller's events are coming from data generated in an Isolate.这是两个控制器,其中ever工作人员正在监听另一个 controller 的事件,该控制器的事件来自隔离中生成的数据。

I'm not aware of anything special about generating data in an Isolate as opposed to any other async data source, but I'm not overly familiar with Isolates.与任何其他异步数据源相比,我不知道在 Isolate 中生成数据有什么特别之处,但我对 Isolates 并不太熟悉。

Controllers控制器

class SplashX extends GetxController {
  ItemsX itemsX;

  SplashX({this.itemsX});

  @override
  void onInit() {
    super.onInit();

    ever(itemsX.items, (items) => print('Received items: $items'));
  }
}

class ItemsX extends GetxController {
  RxList<String> items = RxList<String>();

  void add(String item) {
    items.add(item);
  }

  /// Only relevant for SimplePage at bottom
  List<Widget> get texts => items.map((item) => Text('$item')).toList();
}

Page /w Isolate页 /w 隔离

And here's the edits to the Isolate snippet which you're using.这是您正在使用的Isolate 片段的编辑。 I've instantiated ItemsX controller as a field and SplashX in onInit.我已经将 ItemsX controller 实例化为一个字段,并在 onInit 中实例化了 SplashX。 (There shouldn't be a need to use Stateful Widgets since you can put all state into a Controller, but I didn't want to rewrite the Isolate example). (应该不需要使用有状态小部件,因为您可以将所有 state 放入 Controller,但我不想重写隔离示例)。

class _MyHomePageState extends State<MyHomePage> {
  Isolate _isolate;
  bool _running = false;
  static int _counter = 0;
  String notification = "";
  ReceivePort _receivePort;
  ItemsX ix = Get.put(ItemsX()); // Instantiate ItemsController

  @override
  void initState() {
    super.initState();
    SplashX sx = Get.put(SplashX(itemsX: ix));
    // ↑ Instantiate SplashCont with ever worker
  }

Change to the _handleMessage method:更改为 _handleMessage 方法:

  void _handleMessage(dynamic data) {
    //print('RECEIVED: ' + data);

    ix.add(data); // update observable

    setState(() {
      notification = data;
    });
  }

And finally the debug output results showing ever worker handling observable events ( Received items... ):最后是调试 output 结果显示ever处理可观察事件的工作人员( Received items... ):

[GETX] "ItemsX" has been initialized
[GETX] "SplashX" has been initialized
I/flutter (19012): SEND: notification 1
I/flutter (19012): Received items: [notification 1]
I/flutter (19012): SEND: notification 2
I/flutter (19012): Received items: [notification 1, notification 2]
I/flutter (19012): SEND: notification 3
I/flutter (19012): Received items: [notification 1, notification 2, notification 3]
I/flutter (19012): done!

Controllers in Non-Isolate Page非隔离页面中的控制器

Example of using the same controllers above, without the noise of a Stateful Widget page and all the Isolate stuff.使用上述相同控制器的示例,没有 Stateful Widget 页面和所有 Isolate 的噪音。

class SplashX extends GetxController {
  ItemsX itemsX;

  SplashX({this.itemsX});

  @override
  void onInit() {
    super.onInit();

    ever(itemsX.items, (items) => print('Received items: $items'));
  }
}

class ItemsX extends GetxController {
  RxList<String> items = RxList<String>();

  void add(String item) {
    items.add(item);
  }

  /// Only relevant for SimplePage
  List<Widget> get texts => items.map((item) => Text('$item')).toList();
}

class SimplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    ItemsX ix = Get.put(ItemsX());
    SplashX sx = Get.put(SplashX(itemsX: ix));

    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            Expanded(
              flex: 10,
              child: Obx(
                    () => ListView(
                  children: ix.texts,
                ),
              ),
            ),
            Expanded(
              flex: 1,
              child: RaisedButton(
                child: Text('Add'),
                onPressed: () => ix.add('more...'),
              )
            )
          ],
        ),
      ),
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM