Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get.snackbar() doesn't work successfully when starting the app for the first time. #3055

Open
EricMoin opened this issue Mar 14, 2024 · 3 comments
Assignees

Comments

@EricMoin
Copy link

Description

  • I wanna imitate a splash screen when starting the app for the first time.
  • The following is my code:
/// main.dart
import 'package:flutter/material.dart';
import 'package:byr_flutter/router/byr_router.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
void main() async {
  await GetStorage.init();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      getPages: BYRRouter.routes,
      initialRoute: BYRRouter.welcome,
      theme: ThemeData(
          primaryColor: BYRTheme.greyBackgroundColor,
          colorScheme: ColorScheme.light(
              primary: Colors.white
          ),
          scaffoldBackgroundColor: BYRTheme.greyBackgroundColor
      ),
      home: ScreenUtilInit(
        minTextAdapt: true,
        splitScreenMode: true,
        designSize: const Size(375, 812),
        child: WelcomeScreen(),
      ),
    );
  }
}
/// welcome_screen.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class WelcomeScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => WelcomeScreenState();
}
class WelcomeScreenState extends State<WelcomeScreen>{
  @override
  void initState() {
    super.initState();
    Get.snackbar('Title','message');
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: (){

        },
        child: Container(
          decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage('resources/images/bbs_ipxmax.png'),
                fit: BoxFit.fill
              )
          ),
        ),
      )
    );
  }
}
  • But it is doesn't work successfully.The log is showed:
E/flutter (15858): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: visitChildElements() called during build.
E/flutter (15858): The BuildContext.visitChildElements() method can't be called during build because the child list is still being updated at that point, so the children might not be constructed yet, or might be old children that are going to be replaced.
E/flutter (15858): #0      Element.visitChildElements.<anonymous closure> (package:flutter/src/widgets/framework.dart:3710:7)
E/flutter (15858): #1      Element.visitChildElements (package:flutter/src/widgets/framework.dart:3719:6)
E/flutter (15858): #2      GetNavigation.overlayContext (package:get/get_navigation/src/extension_navigation.dart:1148:40)
E/flutter (15858): #3      SnackbarController._configureOverlay (package:get/get_navigation/src/snackbar/snackbar_controller.dart:91:36)
E/flutter (15858): #4      SnackbarController._show (package:get/get_navigation/src/snackbar/snackbar_controller.dart:331:5)
E/flutter (15858): #5      GetQueue._check (package:get/get_utils/src/queue/get_queue.dart:42:47)
E/flutter (15858): #6      GetQueue.add (package:get/get_utils/src/queue/get_queue.dart:29:5)
E/flutter (15858): #7      _SnackBarQueue._addJob (package:get/get_navigation/src/snackbar/snackbar_controller.dart:357:31)
E/flutter (15858): #8      SnackbarController.show (package:get/get_navigation/src/snackbar/snackbar_controller.dart:63:27)
E/flutter (15858): #9      ExtensionSnackbar.snackbar (package:get/get_navigation/src/extension_navigation.dart:465:18)
E/flutter (15858): #10     WelcomeScreenState.initState (package:byr_flutter/features/screens/login/welcome_screen.dart:22:9)
E/flutter (15858): #11     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5611:55)
E/flutter (15858): #12     ComponentElement.mount (package:flutter/src/widgets/framework.dart:5456:5)
E/flutter (15858): #13     Element.inflateWidget (package:flutter/src/widgets/framework.dart:4335:16)
E/flutter (15858): #14     Element.updateChild (package:flutter/src/widgets/framework.dart:3840:20)
E/flutter (15858): #15     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5505:16)
E/flutter (15858): #16     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5643:11)
E/flutter (15858): #17     Element.rebuild (package:flutter/src/widgets/framework.dart:5196:7)
E/flutter (15858): #18     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2904:19)
E/flutter (15858): #19     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:989:21)
E/flutter (15858): #20     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:448:5)
E/flutter (15858): #21     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1386:15)
E/flutter (15858): #22     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1311:9)
E/flutter (15858): #23     SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1034:7)
E/flutter (15858): #24     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
E/flutter (15858): #25     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
E/flutter (15858): #26     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
E/flutter (15858): #27     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
E/flutter (15858): 

  • If I want to jump to another page by Get.toNamed() forcelly, a new error is thrown when I called Get.back() in new page.
E/flutter (15858): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: LateInitializationError: Field '_controller@954359576' has not been initialized.
E/flutter (15858): #0      SnackbarController._controller (package:get/get_navigation/src/snackbar/snackbar_controller.dart)
E/flutter (15858): #1      SnackbarController._removeEntry (package:get/get_navigation/src/snackbar/snackbar_controller.dart:314:7)
E/flutter (15858): #2      SnackbarController.close (package:get/get_navigation/src/snackbar/snackbar_controller.dart:55:5)
E/flutter (15858): #3      _SnackBarQueue._closeCurrentJob (package:get/get_navigation/src/snackbar/snackbar_controller.dart:370:29)
E/flutter (15858): #4      SnackbarController.closeCurrentSnackbar (package:get/get_navigation/src/snackbar/snackbar_controller.dart:340:26)
E/flutter (15858): #5      GetNavigation.closeCurrentSnackbar (package:get/get_navigation/src/extension_navigation.dart:1124:30)
E/flutter (15858): #6      GetNavigation.back (package:get/get_navigation/src/extension_navigation.dart:822:7)
E/flutter (15858): #7      UserSettingScreenState.build.<anonymous closure> (package:byr_flutter/features/screens/user/user_setting_screen.dart:37:32)
E/flutter (15858): #8      _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1183:21)
E/flutter (15858): #9      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:315:24)
E/flutter (15858): #10     TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:652:11)
E/flutter (15858): #11     BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:309:5)
E/flutter (15858): #12     BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:242:7)
E/flutter (15858): #13     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:670:9)
E/flutter (15858): #14     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:98:12)
E/flutter (15858): #15     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:143:9)
E/flutter (15858): #16     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
E/flutter (15858): #17     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:141:18)
E/flutter (15858): #18     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:127:7)
E/flutter (15858): #19     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:495:19)
E/flutter (15858): #20     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:475:22)
E/flutter (15858): #21     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:430:11)
E/flutter (15858): #22     GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:420:7)
E/flutter (15858): #23     GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:383:5)
E/flutter (15858): #24     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:330:7)
E/flutter (15858): #25     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:299:9)
E/flutter (15858): #26     _invoke1 (dart:ui/hooks.dart:328:13)
E/flutter (15858): #27     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:429:7)
E/flutter (15858): #28     _dispatchPointerDataPacket (dart:ui/hooks.dart:262:31)
  • Only when I call Get.back() I can meet this problem,but other methods are OK.

Solution(not good)

  • Well , I search for a long time for the problem.Certainly I know to write in another way is the better solution.So I change my code:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class WelcomeScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => WelcomeScreenState();
}
class WelcomeScreenState extends State<WelcomeScreen>{
  @override
  void initState() {
    super.initState();
    Future.delayed(const Duration(seconds: 2),(){
      Get.snackbar('title','message');
      if( KeyDao.isLoginInfoSaved ){
        Solver.emit(
          future: () => Repository.postAuthInfo(),
          onSuccess: (result){
            // Get.closeAllSnackbars();
            Get.toNamed(BYRRouter.main);
          }
        );
      }else{
        Get.toNamed(BYRRouter.login);
      }
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onTap: (){

        },
        child: Container(
          decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage('resources/images/bbs_ipxmax.png'),
                fit: BoxFit.fill
              )
          ),
        ),
      )
    );
  }
}
  • But the splash screen should not show snackbar when the user enter app for the first time.
  • What's the best solution for this?
@GotJimmy
Copy link

I had the same problem when calling snackbar from the main() function, but moving the snackbar call to onInit of a GetXController class that gets created during application startup did the trick and now works perfectly on startup.

@jonataslaw
Copy link
Owner

Well, let me explain what's going on:

At the time you called the snackbar, the widget tree Overlay was not ready yet.
If you use the Snackbar in main(), or onInit(), or initState(), it will trigger an error, perhaps this is not so obvious, but all of this is called before the build process is completed, so how do you Will display a widget if the tree is not ready yet?

But I'm here to give you the solution:

  1. I'm using Get.snackbar() in onInit():
  • Just stop! Use in onReady, this function was created for this.
  1. I'm using Get.snackbar() in main():
  • I recommend you look for a better place to insert your snackbar, but it will work with tip 3, in the same way. So If you really need it, just follow it.
  1. I'm using it in initState (or main()), and I can't change it.
  • There is a native feature (which is also documented) that solves this with a single parameter:
    Get.snackbar("dsds", "dsds",instantInit: false);

instantInit: false will wait for the widget tree to be ready and send the snackbar.

Hope this helps.

@GotJimmy
Copy link

Thanks @jonataslaw for this precise feedback. Already implemented this with suggestions 1 & 3. Works perfectly!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants