如何解决在小部件外使用 GetX 观察列表
我有一个隔离,做了一些繁重的计算,然后在接收到结果的列表时运行一个 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 并且它不为空),但在添加项目时不会触发飞溅控制器上的工作人员。
我在这里做错了什么?这是使用 Getx 在小部件之外观察变量的正确方法吗? 任何人都可以帮我解决这个问题吗?
编辑:在项目控制器中,我以这种方式添加项目
add(item) => items.add(item)
解决方法
继续使用 Isolate example,但不使用 StatefulWidget,即不使用 setState。
SplashX 中的 ever
worker 将接收从 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),);
}
}
,
这里有两个控制器,其中一个 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
worker 处理可观察事件 (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!
非隔离页面中的控制器
使用上述相同控制器的示例,没有 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...'),)
)
],);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。