Reputation: 31
I trying add error on Getx Rx at catch
block and get it on my stream builder, but a got the error below and the progress indicator keep running forever:
[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):
Here is the code I use to reproduce the error:
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,
);
}),
);
}
}
Updated
I moved to stable channel and it work as it was answered at comment.
Upvotes: 1
Views: 8547
Reputation: 5595
So with what you have here you're not really using GetX you're basically using standard dart streams. You don't need to pass around Getx Controllers. I suggest reading up on their docs to do proper controller init and access anywhere in the app.
Easiest way to show "loading" while data is loading using Getx is with an RxBool and a GetX widget that reacts to observable variables, either GetX or Obx widget. I also don't see the value of a getter here if the whole point is to access the value of the variable and display it on screen. The handle error in the onInit of the HomeController will catch any stream errors and you can do what you need to do there. But the code below will show "loading..." for the specified duration in your load function.
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),
)),
);
}
}
Upvotes: 1