我的flutter项目中多次使用了GlobalKey

问题描述 投票:0回答:1

我的项目遇到问题。
我使用 Flutter 和 GetX 来创建路由。
现在这是一个简单的项目,但是当我在 VS 中刷新此代码时出现错误。

我在 Chrome 浏览器上检查我的项目,我的调试器中有此信息:

This app is linked to the debug service: ws://127.0.0.1:49847/Kvc6Hh7Hagk=/ws
Debug service listening on ws://127.0.0.1:49847/Kvc6Hh7Hagk=/ws
Connecting to VM Service at ws://127.0.0.1:49847/Kvc6Hh7Hagk=/ws
***** Supabase init completed Instance of 'Supabase'
***** SupabaseDeepLinkingMixin startAuthObserver
**** onAuthStateChange: AuthChangeEvent.initialSession
[GETX] Instance "GetMaterialController" has been created
[GETX] Instance "GetMaterialController" has been initialized
[GETX] GOING TO ROUTE /splashpage
[GETX] GOING TO ROUTE /LoginScreen
[GETX] REMOVING ROUTE /splashpage

我的项目是这样工作的 - 第一个用户转到splashScreen - 如果他登录,那么他会转到 HomePage() ,如果没有登录,他将被重定向到 /LoginScreen()。

目前我不知道为什么 /spashpage 是两次,但项目没有问题。

没有错误 - 一切正常。 然后,当我上传一些新的代码元素(例如,我添加了简单的更改)并保存该项目时,我的 VS 中进行了热重载,但出现了错误:
1)

 ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following TypeErrorImpl was thrown building _FocusInheritedScope:
Unexpected null value.

The relevant error-causing widget was:
  Directionality
  Directionality:file://.pub-cache/hosted/pub.dev/get-4.6.6/lib/get_navigation/src/root/get_material_app.dart:328:12

我的 main.dart 文件中出现第二个错误?

Another exception was thrown: A GlobalKey was used multiple times inside one widget's child list.
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building _FocusInheritedScope:
A GlobalKey was used multiple times inside one widget's child list.
The offending GlobalKey was: [LabeledGlobalKey<NavigatorState>#c60d4 Key Created by default]
The parent of the widgets with that key was:
  _FocusInheritedScope
The first child to get instantiated with that key became:
  Navigator-[LabeledGlobalKey<NavigatorState>#c60d4 Key Created by default]
The second child that was to be instantiated with that key was:
  _FocusInheritedScope
A GlobalKey can only be specified on one widget at a time in the widget tree.

也许代码会有所帮助

main.dart

import 'package:get/get.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Supabase.initialize(
    url: 'url key',
    anonKey:
        'my anon key',
    debug: true,
  );
  runApp(MyApp());
}

final supabase = Supabase.instance.client;

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      initialRoute: '/splashpage',
      getPages: [
        GetPage(name: '/splashpage', page: () => SplashPage()),
        GetPage(name: '/loginpage', page: () => LoginScreen()),
        GetPage(name: '/homepage', page: () => HomePage()),
      ],
      title: 'Flutter Admin Panel2',
      theme: lightMode,
      darkTheme: darkMode,
    );
  }
}

登录页面.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';

class LoginScreen extends StatelessWidget {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  double displayHeight(BuildContext context) {
    return displaySize(context).height;
  }

  double displayWidth(BuildContext context) {
    return displaySize(context).width;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          Container(
            padding: EdgeInsets.all(24),
            width: 400,
            height: double.maxFinite,
            decoration: BoxDecoration(
              border: Border(
                right: BorderSide(
                  color: Colors.blue.shade300,
                  width: 1,
                ),
              ),
              color: Colors.white,
              boxShadow: [
                BoxShadow(
                  color: Colors.grey.withOpacity(0.5),
                  spreadRadius: 5,
                  blurRadius: 7,
                  offset: Offset(0, 3),
                ),
              ],
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Image.asset('assets/images/$logo', width: 200, height: 200),
                SizedBox(height: 50),
                TextField(
                  key: Key('email-field'),
                  controller: _emailController,
                  decoration: textFieldDecoration.copyWith(labelText: 'Email'),
                ),
                SizedBox(height: 20),
                TextField(
                  key: Key('password-field'),
                  controller: _passwordController,
                  obscureText: true,
                  decoration:
                      textFieldDecoration.copyWith(labelText: 'Password'),
                ),
                SizedBox(height: 20),
                Container(
                  width: 200,
                  height: 50,
                  child: ElevatedButton(
                    style: buttonStyle1,
                    onPressed: () async {
                      try {
                        final email = _emailController.text.trim();
                        final password = _passwordController.text.trim();

                        if (email.isEmpty || password.isEmpty) {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(
                              content:
                                  Text('Email and password cannot be empty.'),
                              backgroundColor: Colors.red,
                            ),
                          );
                          return;
                        }

                        final response = await supabase.auth.signInWithPassword(
                            email: email, password: password);

                        if (response.user != null) {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(
                              content: Text('Login Success'),
                              backgroundColor: Colors.green,
                            ),
                          );
                          Get.to(() => HomePage());
                        } else {
                          ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(
                              content: Text('Login failed, please try again.1'),
                              backgroundColor: Colors.red,
                            ),
                          );
                        }
                      } catch (error) {
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(
                            content:
                                Text('An error occurred: ${error.toString()}'),
                            backgroundColor: Colors.red,
                          ),
                        );
                      }
                    },
                    child: Text('Login'),
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: displayWidth(context) - 400,
            height: double.maxFinite,
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage('assets/images/background_image.jpg'),
                fit: BoxFit.cover,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

和splash_page.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

class SplashPage extends StatefulWidget {
  const SplashPage({super.key});

  @override
  State<SplashPage> createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _redirect();
    });
  }

  Future<void> _redirect() async {
    // Zasymulowany opóźniony czas ładowania, aby zobaczyć CircularProgressIndicator
    await Future.delayed(const Duration(seconds: 2));
    final session = Supabase.instance.client.auth.currentSession;
    if (!mounted) return;
    if (session != null) {
      Get.offAll(() => HomePage());
    } else {
      Get.offAll(() => LoginScreen());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: const <Widget>[
            CircularProgressIndicator(),
            SizedBox(height: 20),
            Text('Loading...'),
          ],
        ),
      ),
    );
  }
}

如你所见,代码并不大,但一开始就有问题。
重要提示:当我停止项目并再次运行该项目时,不会出现问题。
但是,当我对代码进行一些小的更改并热重新加载我的项目时,就会出现问题(例外)。

你知道出了什么问题吗?

感谢您的时间和帮助

flutter dart flutter-getx
1个回答
0
投票
  1. 尝试停止并重新运行应用程序,而不是热重载。
  2. 如果您在应用程序刚启动时遇到错误:将“/”路由添加到路由列表中并重新启动。
  3. 尝试使您的 GlobalKey 成为“最终”。我认为您的全局密钥是可变的这一事实可能会造成这个问题。
  4. 您正在使用 Getx 和 flutter,如果您尝试访问“AppPages”中未定义的路由,那么您可能会收到此错误:

Error : A global key was used multiple times inside one widgets child

解决方案是您需要在 GetMaterialApp 中定义“unknownRoute”,如下所示:

unknownRoute: GetPage(
          name: "/splash",
          page: () => SplashView(),
          binding: SplashBinding(),
        ),

您可以定义自己的视图和路线名称。 希望它有帮助,快乐编码!

© www.soinside.com 2019 - 2024. All rights reserved.