Как добавить ошибку в 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),
          )),
    );
  }
}


Другие вопросы по тегам