Как добавить ошибку в Getx Rx <String> и получить ее в построителе потоков?
Я пытаюсь добавить ошибку в Getx Rx на
catch
block и получить его в моем конструкторе потоков, но возникла ошибка ниже, а индикатор выполнения продолжает работать вечно:
[GETX] GOING TO ROUTE /
[GETX] REMOVING ROUTE /login
E/flutter ( 5129): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: Closure call with mismatched arguments: function '_StreamBuilderBaseState._subscribe.<anonymous closure>'
E/flutter ( 5129): Receiver: Closure: (Object, StackTrace) => Null
E/flutter ( 5129): Tried calling: _StreamBuilderBaseState._subscribe.<anonymous closure>("error")
E/flutter ( 5129): Found: _StreamBuilderBaseState._subscribe.<anonymous closure>(Object, StackTrace) => Null
E/flutter ( 5129): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
E/flutter ( 5129): #1 GetStream._notifyError [package:get/…/rx_stream/get_stream.dart]
E/flutter ( 5129): #2 GetStream.addError [package:get/…/rx_stream/get_stream.dart]
E/flutter ( 5129): #3 _RxImpl.addError [package:get/…/rx_core/rx_impl.dart]
E/flutter ( 5129): #4 HomeController.load [package:testegetx/main.dart]
E/flutter ( 5129): <asynchronous suspension>
E/flutter ( 5129):
Вот код, который я использую для воспроизведения ошибки:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetMaterialApp(
title: 'App',
initialRoute: '/login',
getPages: [
GetPage(name: '/login', page: () => LoginPage()),
GetPage(name: '/', page: () => HomePage(HomeController())),
],
);
}
}
class LoginPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
Get.offAllNamed('/');
},
child: Text('Go Home'),
),
),
);
}
}
class HomeController {
final _text = Rx<String>();
Stream<String> get textStream => _text.stream;
Future<void> load() async {
try {
await Future.delayed(Duration(seconds: 2));
throw Error();
} catch (e) {
_text.addError('error');
}
}
}
class HomePage extends StatelessWidget {
final HomeController controller;
HomePage(this.controller);
@override
Widget build(BuildContext context) {
controller.load();
return Scaffold(
body: StreamBuilder<String>(
stream: controller.textStream,
builder: (context, snapshot) {
Widget child;
if (snapshot.hasError) {
child = Text(snapshot.error);
} else if (!snapshot.hasData) {
child = Text('loading...');
} else {
child = Text(snapshot.data);
}
return Center(
child: child,
);
}),
);
}
}
1 ответ
Итак, с тем, что у вас есть, вы на самом деле не используете GetX, вы в основном используете стандартные потоки дротиков. Вам не нужно передавать контроллеры Getx. Я предлагаю прочитать их документацию, чтобы правильно запустить контроллер и получить доступ в любом месте приложения.
Самый простой способ показать «загрузку» во время загрузки данных с помощью Getx - использовать RxBool и виджет GetX, который реагирует на наблюдаемые переменные, будь то виджет GetX или Obx. Я также не вижу здесь значения геттера, если все дело в том, чтобы получить доступ к значению переменной и отобразить его на экране. Ошибка дескриптора в onInit HomeController перехватит любые ошибки потока, и вы сможете делать то, что вам нужно там. Но в приведенном ниже коде будет отображаться «загрузка ...» в течение указанного времени в вашей функции загрузки.
class HomeController extends GetxController {
RxString text = ''.obs;
RxBool isLoading = true.obs;
@override
onInit() {
super.onInit();
text.stream.handleError(() {
// handle your error here
});
}
Future<void> load() async {
try {
await Future.delayed(Duration(seconds: 2));
isLoading.value = false;
throw Error();
} catch (e) {
text.addError('error');
}
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final controller = Get.put(HomeController());
controller.load();
return Scaffold(
body: Obx(() => Center(
child: controller.isLoading.value
? Text('loading...')
: Text(controller.text.value),
)),
);
}
}