Flutter Bug,我必须点击按钮两次

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

我在 Flutter 中遇到了这个奇怪的问题。我使用“Provider”进行状态管理,在帮助程序类中一切都很好,我正在发送请求并且收到响应,没有任何问题。问题发生在按钮事件处理程序中。我第一次单击该按钮时几乎没有任何反应,当我第二次单击该按钮时,它会与 API 对话并获取数据。另一个问题是:当我输入正确的数据并将它们发送到 API 时,紧接着我输入了错误的凭据,应用程序告诉我我已经输入了正确的凭据,就好像我正在处理之前的同一个对象一样。 这是我的前端部分代码:

class _LoginPageState extends State<LoginPage> {
  String? myError;
  @override
  Widget build(BuildContext context) {
    double screenWidth = MediaQuery.of(context).size.width;
    TextEditingController userNameController = TextEditingController();
    TextEditingController passwordController = TextEditingController();

    return Directionality(
      textDirection: TextDirection.rtl,
      child: Consumer<PicoProvider>(
        builder: (context, prov, child) => SafeArea(
          child: Scaffold(
            backgroundColor: CustomColors.scaffoldDark,
            body: Padding(
              padding: const EdgeInsets.all(100),
              child: SingleChildScrollView(
                child: Container(
                  width: screenWidth,
                  child: Form(
                    autovalidateMode: AutovalidateMode.onUserInteraction,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: [
                        Container(
                          decoration: BoxDecoration(
                              color: Colors.black,
                              borderRadius: BorderRadius.circular(10),
                              boxShadow: [
                                BoxShadow(
                                  color: Colors.grey.withOpacity(0.5),
                                  spreadRadius: 5,
                                  blurRadius: 7,
                                  offset: const Offset(0, 3),
                                ),
                              ]),
                          child: Image.asset(
                            'assets/images/main_logo.jpeg',
                            height: 300,
                          ),
                        ),
                        const SizedBox(height: 20),
                        CTextField(
                            label: 'اسم المسخدم',
                            icon: Ionicons.person,
                            isObsecured: false,
                            controller: userNameController),
                        const SizedBox(height: 20),
                        CTextField(
                            label: 'كلمة المرور',
                            icon: Ionicons.lock_closed,
                            isObsecured: true,
                            controller: passwordController,
                            onSubmitted: () {
                              prov.websiteLogin(userNameController.text,
                                  passwordController.text);
                            }),
                        ElevatedButton(
                            onPressed: () {
                              prov.websiteLogin(userNameController.text,
                                  passwordController.text);

                              prov.errorText!.isNotEmpty
                                  ? giveMeDialog(
                                      context, 'hello', 'not found', 'error')
                                  : giveMeDialog(context, 'hello',
                                      'you are logged', 'success');
                            },
                            child: const Text('Click')),
                        const SizedBox(height: 20),
                        prov.isLoading
                            ? const CircularProgressIndicator()
                            : const SizedBox(),
                        Text('${prov.errorText}')
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  Future<void> giveMeDialog(
      BuildContext context, String title, String message, String icon) {
    return showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text(title),
          content: Directionality(
            textDirection: TextDirection.rtl,
            child: Column(
              children: [
                Text(
                  message,
                  style: const TextStyle(fontSize: 30),
                ),
                Lottie.asset('assets/animations/${icon}_animation.json'),
              ],
            ),
          ),
        );
      },
    );
  }
}

这是我的后端部分代码:

class PicoProvider extends ChangeNotifier {
  String baseURL = 'http://111.11.11.111:1111';

  bool _isLoading = false;
  bool get isLoading => _isLoading;

  User? _user = User();
  User? get user => _user;

  String? _errorText;
  String? get errorText => _errorText;

  Future<void> websiteLogin(String userName, String password) async {
    try {
      String endPoint =
          '$baseURL/PicoLogin?UserName=$userName&Password=$password';
      _isLoading = true;
      notifyListeners();

      var response = await get(Uri.parse(endPoint), headers: {
        "content-type": "application/json",
        "Access-Control-Allow-Origin": "*",
      });

      if (response.statusCode == 200) {
        _user = User.fromJson(jsonDecode(response.body));
        _errorText = '';
      } else {
        _errorText = 'User Not Found';
      }

      _isLoading = false;
      notifyListeners();
    } catch (e) {
      _errorText = e.toString();
      notifyListeners();
      print('Error: ${e.toString()}');
    }
  }
}
flutter dart http provider state-management
1个回答
0
投票

您的问题在这里

                      ElevatedButton(
                        onPressed: () {
                          prov.websiteLogin(userNameController.text,
                              passwordController.text);

                          prov.errorText!.isNotEmpty
                              ? giveMeDialog(
                                  context, 'hello', 'not found', 'error')
                              : giveMeDialog(context, 'hello',
                                  'you are logged', 'success');
                        },

prov.websiteLogin(..
是一个
async
函数,
prov.errorText
只会在一段时间后更新。因此,在您的代码中,您不会等待
websiteLogin
完成并尝试立即显示对话框。因此它总是给出先前执行的结果。

快速非推荐修复:在

websiteLogin
 中添加 
onPressed

的等待
                      ElevatedButton(
                        onPressed: () async {
                          await prov.websiteLogin(userNameController.text,
                              passwordController.text);

                          prov.errorText!.isNotEmpty
                              ? giveMeDialog(

正确的解决方案是使用监听器。您可以使用字段(枚举)“状态”,它将给出加载、成功和失败等状态,并侦听状态字段中的更改并相应地显示对话框。您可以参考如何添加监听器https://stackoverflow.com/a/72168584/1582630

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