在小部件外部使用 GetX 观察列表
Observe List with GetX outside of widget
我有一个 isolate,它进行了一些繁重的计算,然后接收到结果列表 运行 一个 for 循环将它们添加到带有项目 var items = [].obs;
的可观察列表中
问题是我正在尝试从启动控制器观察项目列表,一旦列表!= [] 我将导航到另一个屏幕,所以在 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');
});
}
}
尽管填充了 itemsController.items(在 for 循环之后我打印了 itemsController.items 并且它不为空)添加项目时飞溅控制器上的 worker 不会触发。
我在这里做错了什么?这是使用 Getx 观察小部件外部变量的正确方法吗?
有人可以帮我解决这个问题吗?
编辑:在项目控制器中,我以这种方式添加项目
add(item) => items.add(item)
这里有两个控制器,其中一个 ever
worker 监听另一个控制器的事件,其中该控制器的事件来自 Isolate 中生成的数据。
与任何其他异步数据源相比,我不知道在 Isolate 中生成数据有什么特别之处,但我对 Isolates 并不过分熟悉。
控制器
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();
}
页/w隔离
这是对您正在使用的 Isolate snippet 的编辑。
我在 onInit 中将 ItemsX 控制器实例化为字段和 SplashX。
(不需要使用 Stateful Widgets,因为您可以将所有状态放入 Controller,但我不想重写 Isolate 示例)。
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
}
更改为 _handleMessage 方法:
void _handleMessage(dynamic data) {
//print('RECEIVED: ' + data);
ix.add(data); // update observable
setState(() {
notification = data;
});
}
最后调试输出结果显示 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!
非隔离页面中的控制器
使用上述相同控制器的示例,没有状态小部件页面和所有隔离内容的噪音。
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...'),
)
)
],
),
),
);
}
}
继续 Isolate example,但不使用 StatefulWidget,即不使用 setState。
SplashX 中的 ever
工作人员将接收从 Isolate 生成的项目。 Stateless Widget 页面将显示从 Isolate 发出的最新项目。
SplashController + ever
worker
class SplashX extends GetxController {
ItemsX itemsX;
SplashX({this.itemsX});
@override
void onInit() {
super.onInit();
ever(itemsX.items, (items) => print('Ever items: $items'));
}
}
物品控制器
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();
}
隔离控制器
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;
}
}
}
无状态页面
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),
),
),
);
}
}
我有一个 isolate,它进行了一些繁重的计算,然后接收到结果列表 运行 一个 for 循环将它们添加到带有项目 var items = [].obs;
的可观察列表中问题是我正在尝试从启动控制器观察项目列表,一旦列表!= [] 我将导航到另一个屏幕,所以在 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');
});
}
}
尽管填充了 itemsController.items(在 for 循环之后我打印了 itemsController.items 并且它不为空)添加项目时飞溅控制器上的 worker 不会触发。
我在这里做错了什么?这是使用 Getx 观察小部件外部变量的正确方法吗? 有人可以帮我解决这个问题吗?
编辑:在项目控制器中,我以这种方式添加项目
add(item) => items.add(item)
这里有两个控制器,其中一个 ever
worker 监听另一个控制器的事件,其中该控制器的事件来自 Isolate 中生成的数据。
与任何其他异步数据源相比,我不知道在 Isolate 中生成数据有什么特别之处,但我对 Isolates 并不过分熟悉。
控制器
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();
}
页/w隔离
这是对您正在使用的 Isolate snippet 的编辑。 我在 onInit 中将 ItemsX 控制器实例化为字段和 SplashX。 (不需要使用 Stateful Widgets,因为您可以将所有状态放入 Controller,但我不想重写 Isolate 示例)。
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
}
更改为 _handleMessage 方法:
void _handleMessage(dynamic data) {
//print('RECEIVED: ' + data);
ix.add(data); // update observable
setState(() {
notification = data;
});
}
最后调试输出结果显示 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!
非隔离页面中的控制器
使用上述相同控制器的示例,没有状态小部件页面和所有隔离内容的噪音。
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...'),
)
)
],
),
),
);
}
}
继续 Isolate example,但不使用 StatefulWidget,即不使用 setState。
SplashX 中的 ever
工作人员将接收从 Isolate 生成的项目。 Stateless Widget 页面将显示从 Isolate 发出的最新项目。
SplashController + ever
worker
class SplashX extends GetxController {
ItemsX itemsX;
SplashX({this.itemsX});
@override
void onInit() {
super.onInit();
ever(itemsX.items, (items) => print('Ever items: $items'));
}
}
物品控制器
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();
}
隔离控制器
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;
}
}
}
无状态页面
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),
),
),
);
}
}