flutter scheduler callback errors? - flutter

So I'm running through some tutorials for Flutter Animation, and I had to use something called a Post Frame callback to ensure that function didn't run until after the build function, like so (with the function in question displayed):
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_addTrips();
});
}
void _addTrips() {
// get data from db
List<Trip> _trips = [
Trip(title: 'Beach Paradise', price: '350', nights: '3', img: 'beach.png'),
Trip(title: 'City Break', price: '400', nights: '5', img: 'city.png'),
Trip(title: 'Ski Adventure', price: '750', nights: '2', img: 'ski.png'),
Trip(title: 'Space Blast', price: '600', nights: '4', img: 'space.png'),
];
The build function (within the same initState) looks like this:
#override
Widget build(BuildContext context) {
return AnimatedList(
key: _listKey,
initialItemCount: _tripTiles.length,
itemBuilder: (context, index, animation) {
return SlideTransition(
child: _tripTiles[index],
position: animation.drive(_offset)
);
}
);
}
The items on the list fail to populate when I run the code. The error that I'm getting in the run panel is the following with the stack included:
Exception caught by scheduler library
The following assertion was thrown during a scheduler callback:
'package:flutter/src/widgets/animated_list.dart': Failed assertion: line 963 pos 12:
'itemIndex >= 0 && itemIndex <= _itemsCount': is not true.
Either the assertion indicates an error in the framework itself, or we should provide
substantially more information in this error message to help you determine and fix the
underlying
cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=2_bug.md
When the exception was thrown, this was the stack:
#2 SliverAnimatedListState.insertItem
(package:flutter/src/widgets/animated_list.dart:963:12)
#3 AnimatedListState.insertItem
(package:flutter/src/widgets/animated_list.dart:484:42)
#4 _TripListState._addTrips.<anonymous closure>
(package:ninja_trips/shared/tripList.dart:33:29)
#5 List.forEach (dart:core-patch/growable_array.dart:403:8)
#6 _TripListState._addTrips (package:ninja_trips/shared/tripList.dart:31:12)
#7 _TripListState.initState.<anonymous closure>
(package:ninja_trips/shared/tripList.dart:18:7)
#8 SchedulerBinding._invokeFrameCallback
(package:flutter/src/scheduler/binding.dart:1143:15)
#9 SchedulerBinding.handleDrawFrame
(package:flutter/src/scheduler/binding.dart:1088:9)
#10 SchedulerBinding.scheduleWarmUpFrame.<anonymous closure>
(package:flutter/src/scheduler/binding.dart:863:7)
(elided 13 frames from class _AssertionError, class _RawReceivePortImpl, class _Timer,
dart:async, and dart:async-patch)
The tutorial in question didn't seem to anticipate this as a possibility and I'm pretty stumped so far. Any ideas?
Thanks,
ATD

Related

Unhandled Exception: Null check operator used on a null value in flutter

I hope you are well, I will give you a bit of context about my problem...
I really don't know why this error happens and I've seen many similar publications but they haven't worked for me.
I'm new to flutter and I'm working on an app, but when the user wants to log out, the app crashes and shows the following error:
E/flutter (12659): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value
E/flutter (12659): #0 StatefulElement.state
package:flutter/…/widgets/framework.dart:4999
E/flutter (12659): #1 Navigator.of
package:flutter/…/widgets/navigator.dart:2543
E/flutter (12659): #2 Navigator.pushReplacement
package:flutter/…/widgets/navigator.dart:2105
E/flutter (12659): #3 MainCoordinator.logoutNavigation
package:domicilios/…/MainCoordinator/MainCoordinator.dart:62
E/flutter (12659): #4 UserActions.signOut.<anonymous closure>.<anonymous closure>
package:domicilios/…/View/ProfileTab.dart:222
E/flutter (12659): <asynchronous suspension>
This is the code that generates this error, I hope you can help me, thank you very much for your attention.
this is the class:
extension UserActions on _ProfileTabState {
void signOut(BuildContext context) {
AlertView.showAlertDialog(
model: AlertViewModel(
context,
const AssetImage('assets/logout.png'),
'Cierre de sesión en curso',
"¿Desear salir de la sesión actual?",
'Cerrar sesión',
"Cancelar", () {
_profileTabViewModel
.signOut()
.then((value) => coordinator.logoutNavigation(context: context));
}, () {
Navigator.pop(context);
}));
}
}
That's how I call it in the code:
onTap: () => signOut(context),
This is most likely due to the widget being unmounted before navigating.
You can check if the widget is mounted before navigating.
if (mounted) {
_profileTabViewModel.signOut().then((value) {
if (mounted) {
coordinator.logoutNavigation(context: context);
}
});
}
Also,
if(mounted){
Navigator.pop(context);
}

How can I do contextless navigation in order to move to a maintenance screen in Flutter?

I have a Maintenance controller, that initializez an observable variable, and whenever that variable is true, it navigates to a maintenance screen, and when the variable gets set to false it navigates back as follows:
class MaintenanceController extends GetxController {
RxBool isMaintenance = false.obs;
#override
onInit() {
super.onInit();
ever(
isMaintenance,
(_) => {
if (isMaintenance.value) {Get.offNamed(Routes.maintenance)} else {Get.offNamed(Routes.splash)}
});
}
}
Everything works fine, but I get the following exception in the logs:
flutter: You are trying to use contextless navigation without
a GetMaterialApp or Get.key.
If you are testing your app, you can use:
[Get.testMode = true], or if you are running your app on
a physical device or emulator, you must exchange your [MaterialApp]
for a [GetMaterialApp].
flutter:
#0 GetNavigation.global (package:get/get_navigation/src/extension_navigation.dart:1094:7)
#1 GetNavigation.offNamed (package:get/get_navigation/src/extension_navigation.dart:629:12)
#2 MaintenanceController.onInit.<anonymous closure> (package:n_app/src/screens/maintenance/maintenance_controller.dart:17:85)
#3 ever.<anonymous closure> (package:get/get_rx/src/rx_workers/rx_workers.dart:69:44)
#4 GetStream._notifyData (package:get/get_rx/src/rx_stream/get_stream.dart:47:21)
#5 GetStream.add (package:get/get_rx/src/rx_stream/get_stream.dart:97:5)
#6 RxObjectMixin.value= (package:get/get_rx/src/rx_types/rx_core/rx_impl.dart:105:13)
#7 MaintenanceController.subscribe.<anonymous closure> (package:n_app/src/screens/maintenance/maintenance_controller.dart:29:21)
#8 _rootRunUnary (dart:async/zone.dart:1434:47)
#9 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#10 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#11 _Bufferi<…>
flutter: ----------------------------------------------------
app.dart:
GetMaterialApp(
debugShowCheckedModeBanner: false,
locale: Get.find<LocalizationController>().deviceLocale,
getPages: Routes.routes,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
unknownRoute: Routes.getNotFound,
initialRoute: GetPlatform.isWeb ? Routes.initial : Routes.splash,
theme: Get.find<ThemeController>().themeData,
navigatorKey: NavigationService.navigatorKey,
);
I tried to add the navigatorKey: Get.key and use navigatorKey.currentState!.pushNamed(routeName); to navigate, but the currentState is always null. Any advice?
You have to use GetMaterialApp instead of MaterialApp for the contextless navigation to work in GetX.
Replace
MaterialApp(home: somePage());
with
GetMaterialApp(home: somePage());
Adding navigatorKey: Get.key to the GetMaterialApp and continuing to use Get.offNamed(...) instead of navigatorKey.currentState!.pushNamed(routeName); worked.

Flutter md link not loading md file

I am using the flutter_markdown widget to display help info in my app.
Inside an md file I am using the link to another md file. Both md files are defined in the 'assets' list in the pubspec.yml file
### [Overview](resource:asset/doc/overview.md) / Match Screen ###
Then I'm using the 'onTapLink' event handler to capture the users tap on the link to reset the markup widget to display the new md file like...
Future<String> _getData(String aFileName) async{
return rootBundle.loadString(aFileName);
}
#override
Widget build(BuildContext context) {
// get
return Scaffold(
appBar: AppBar(title: Text('Help')),
body: FutureBuilder<String>(
future: _dataFuture,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Markdown(data: snapshot.data!, onTapLink: (text,href,title) {
setState(() {
_dataFuture = _getData(href!);
});
},);
}
return Center(
child: CircularProgressIndicator(),
);
}),
);
}
However, the onTapLnk code is causing an exception where it can't load the md file name passed in 'hef'
E/flutter ( 7261): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Unable to load asset: resource:asset/doc/overview.md
E/flutter ( 7261): #0 PlatformAssetBundle.load (package:flutter/src/services/asset_bundle.dart:237:7)
E/flutter ( 7261): <asynchronous suspension>
E/flutter ( 7261): #1 AssetBundle.loadString (package:flutter/src/services/asset_bundle.dart:72:27)
E/flutter ( 7261): <asynchronous suspension>
E/flutter ( 7261):
Any suggestions?
Through testing I can separately display both md files, so its nothing to do with faulty asset definition in the pubspec.yml file.
Solved it
The link definition in the md file should be
### [Overview](asset/doc/overview.md) / Match Screen ###
not
### [Overview](resource:asset/doc/overview.md) / Match Screen ###

Dio Interceptor not working on first request in same callback, only subsequent calls

I am testing out dio and tried to add a interceptor to simply add a token to future requests but am getting a weird results I can't seem to fix. All I have as a test is a 2 buttons. One when clicked should log me in and add the token to the interceptor, and the second button requests the auth profile data. For some reason, clicking the log in button I log in fine but get a 403 Forbidden when clicking the second button to access the auth profile data (even though i request the profile data after adding the interceptor). The weird part is that when i click the second button again (without changing any code or even hot reloading) everything works fine and the auth profile data is printed out. Every time I hot restart I get back to this same problem where my first request of the auth profile data has a 403 but subsequent requests work fine. I've been trying to figure out what is going on for a couple hours and cannot understand whats wrong. Please help. Thank you. (The backend is handled by django but the problem cannot be there as the api works with other frameworks and even in dio works fine on subsequent button presses, just not the first)
Code
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
Dio session = Dio(
BaseOptions(
connectTimeout: 30000,
baseUrl: 'http://127.0.0.1:8000',
responseType: ResponseType.json,
contentType: ContentType.json.toString(),
),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
RaisedButton(
child: Text('Log In'),
onPressed: () async {
print('starting');
var res = await session.post('/auth/login/',
data: {'username': 'tester', 'password': 'tester'});
print(res.data);
session.interceptors.clear();
session.interceptors.addAll([
InterceptorsWrapper(
onRequest: (RequestOptions requestOptions) {
session.interceptors.requestLock.lock();
String token = res.data['key'];
if (token != null) {
session.options.headers[HttpHeaders.authorizationHeader] =
‘token $token’;
}
session.interceptors.requestLock.unlock();
return requestOptions;
},
onError: (e) => print(e.message),
),
]);
print(session.interceptors);
}),
RaisedButton(
child: Text('Get Profile'),
onPressed: () async {
session.get('/api/auth/').then((res) => print(res.data));
}),
],
),
),
);
}
}
Console on clicking the log in button
Restarted application in 11,586ms.
flutter: starting
flutter: {key: 745c0a53112e61d54bea5ea725f7fa92e3a2cdbb}
flutter: [Instance of 'InterceptorsWrapper']
Console on the first time clicking the get profile button
flutter: Http status error [403]
[VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: DioError [DioErrorType.RESPONSE]: Http status error [403]
#0 DioMixin._request._errorInterceptorWrapper.<anonymous closure>.<anonymous closure>.<anonymous closure>
package:dio/src/dio.dart:870
#1 _rootRunUnary (dart:async/zone.dart:1198:47)
#2 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
#3 _FutureListener.handleValue (dart:async/future_impl.dart:143:18)
#4 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:696:45)
#5 Future._propagateToListeners (dart:async/future_impl.dart:725:32)
#6 Future._completeWithValue (dart:async/future_impl.dart:529:5)
#7 Future._asyncCompleteWithValue.<anonymous closure> (dart:async/future_impl.dart:567:7)
#8 _rootRun (dart:async/zone.dart:1190:13)
#9 _CustomZone.run (dart:async/zone.dart:1093:19)
#10 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
#11 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zon<…>
Console on subsequent times clicking the get profile button
flutter: {id: 3, username: tester, first_name: , last_name: , email: tester#tester.com}
5 more hours and finally figured out the problem.
session.options.headers[HttpHeaders.authorizationHeader] = 'token ' + token;
should be
requestOptions.headers[HttpHeaders.authorizationHeader] = 'token ' + token;

Navigator.removeRoute & Navigator.removeRouteBelow

There are two functions in Navigator.dart, removeRoute and removeRouteBelow. I don't know how to use these two methods. This is the page route: / -> A -> B -> C -> D. And I perform this code in page D:
Navigator.removeRoute(context, MaterialPageRoute(builder: (context) => PushPageB()));
But there goes something wrong:
══╡ EXCEPTION CAUGHT BY GESTURE ╞═════════════════════════════════
The following assertion was thrown while handling a gesture:
'package:flutter/src/widgets/navigator.dart': Failed assertion: line 1832 pos 12: 'route._navigator
== this': is not true.
Either the assertion indicates an error in the framework itself, or we should provide substantially
more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new
When the exception was thrown, this was the stack:
2 NavigatorState.removeRoute (package:flutter/src/widgets/navigator.dart:1832:12)
3 Navigator.removeRoute (package:flutter/src/widgets/navigator.dart:1221:34)
4 PushPageE.build.<anonymous closure> (package:flutter_navigation/push_page_1.dart:223:29)
5 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
6 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
7 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
8 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
9 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
10 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
11 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
12 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
13 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:143:19)
14 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
15 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
16 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
17 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
18 _invoke1 (dart:ui/hooks.dart:153:13)
19 _dispatchPointerDataPacket (dart:ui/hooks.dart:107:5)
(elided 2 frames from class _AssertionError)
Handler: onTap
Recognizer:
TapGestureRecognizer#2a91c(debugOwner: GestureDetector, state: possible, won arena, finalPosition:
Offset(211.1, 411.1), sent tap down)
══════════════════════════════════════════════════════════════════
I don't know why would this happened, and how use these two methods correctly.
The MaterialPageRoute you have created inside Navigator.removeRoute call has no connection to the Navigator because it wasn't pushed yet. Therefore you've got an error.
In order to use removeRoute method correctly you need to remeber a route you pushed to the Navigator.
I am using following code to keep just one instance of a page in the Navigator.
var filterRoutes = <String, MaterialPageRoute<dynamic>>{'page1': null, 'page2': null, 'page3': null, 'page4': null};
MaterialPageRoute getNextRoute(BuildContext context, String nextPage) {
var route;
switch (nextPage) {
case 'page1':
route = MaterialPageRoute(builder: (context) => Page1());
break;
case 'page2':
route = MaterialPageRoute(builder: (context) => Page2());
break;
case 'page3':
route = MaterialPageRoute(builder: (context) => Page3());
break;
case 'page4':
route = MaterialPageRoute(builder: (context) => Page4());
break;
default:
route = MaterialPageRoute(builder: (context) => SomeOtherPage());
}
if (nextPage != null) {
if (filterRoutes[nextPage] != null) {
Navigator.removeRoute(context, filterRoutes[nextPage]);
}
filterRoutes[nextPage] = route;
}
return route;
}
If you want to remove blow router and go to new route like logout from setting and go to login page, you can do this:
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) =>
LoginScreen()), (Route<dynamic> route) => false);