Flutter/dart:解析服务器 sdk:ParseUser.currentUser() 函数在重置时返回 null

Flutter/dart: Parse Server sdk: ParseUser.currentUser() function returning null on reset

我在我的 flutter 应用程序中使用带有“back4app”的“Parse Server sdk”作为后端,我在使用以下函数首次启动应用程序时无法调用当前用户:“ParseUser.currentUser ()" 但出于某种原因,即使在我重新启动应用程序时登录后,函数 returns null

pubspec.yaml

dependencies:
  parse_server_sdk: ^2.1.0

Main.dart

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

  final keyApplicationId = 'xxxxxxxxx';
  final keyParseServerUrl = 'https://parseapi.back4app.com';
  final keyClientkey = 'xxxxxxxxxx';

  await Parse().initialize(
      keyApplicationId,
      keyParseServerUrl,
    clientKey: keyClientkey,
    debug: true
  );

  print('connected to Parse Server');

  runApp(MyApp());
}



class MyApp extends StatelessWidget {
  Future<bool> hasUserLogged() async {
    print('future called');
    ParseUser currentUser = await ParseUser.currentUser() as ParseUser;
    if (currentUser == null) {
      return false;
    }
    //Validates that the user's session token is valid
    final ParseResponse parseResponse =
    await ParseUser.getCurrentUserFromServer(
        currentUser.get<String>('sessionToken'));

    if (!parseResponse.success) {
      print('call failed');
      //Invalid session. Logout
      await currentUser.logout();
      return false;
    } else {
      print('user found');
      return true;
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter - Parse Server',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: FutureBuilder<bool>(
          future: hasUserLogged(),
          builder: (context, snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.none:
              case ConnectionState.waiting:
                return Scaffold(
                  body: Center(
                    child: Container(
                        width: 100,
                        height: 100,
                        child: CircularProgressIndicator()),
                  ),
                );
              default:
                if (snapshot.hasData && snapshot.data) {
                  print('to User');
                  return UserPage();
                } else {
                  print('to Login');
                  return LoginPage();
                }
            }
          }),
    );
  }
}

登录页面:

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final controllerUsername = TextEditingController();
  final controllerPassword = TextEditingController();
  bool isLoggedIn = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Flutter - Parse Server'),
        ),
        body: Center(
          child: SingleChildScrollView(
            padding: const EdgeInsets.all(8),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Container(
                  height: 200,
                  child: Image.network(
                      'https://blog.back4app.com/wp-content/uploads/2017/11/logo-b4a-1-768x175-1.png'),
                ),
                Center(
                  child: const Text('Flutter on Back4App',
                      style:
                      TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                ),
                SizedBox(
                  height: 16,
                ),
                TextField(
                  controller: controllerUsername,
                  enabled: !isLoggedIn,
                  keyboardType: TextInputType.text,
                  textCapitalization: TextCapitalization.none,
                  autocorrect: false,
                  decoration: InputDecoration(
                      border: OutlineInputBorder(
                          borderSide: BorderSide(color: Colors.black)),
                      labelText: 'Username'),
                ),
                SizedBox(
                  height: 8,
                ),
                TextField(
                  controller: controllerPassword,
                  enabled: !isLoggedIn,
                  obscureText: true,
                  keyboardType: TextInputType.text,
                  textCapitalization: TextCapitalization.none,
                  autocorrect: false,
                  decoration: InputDecoration(
                      border: OutlineInputBorder(
                          borderSide: BorderSide(color: Colors.black)),
                      labelText: 'Password'),
                ),
                SizedBox(
                  height: 16,
                ),
                Container(
                  height: 50,
                  child: ElevatedButton(
                    child: const Text('Login'),
                    onPressed: isLoggedIn ? null : () => doUserLogin(),
                  ),
                ),
                SizedBox(
                  height: 16,
                ),
                Container(
                  height: 50,
                  child: ElevatedButton(
                    child: const Text('Sign Up'),
                    onPressed: () => navigateToSignUp(),
                  ),
                ),
                SizedBox(
                  height: 16,
                ),
                Container(
                  height: 50,
                  child: ElevatedButton(
                    child: const Text('Reset Password'),
                    onPressed: () => navigateToResetPassword(),
                  ),
                )
              ],
            ),
          ),
        ));
  }

  void doUserLogin() async {
    final username = controllerUsername.text.trim();
    final password = controllerPassword.text.trim();

    final user = ParseUser(username, password, null);

    var response = await user.login();

    if (response.success) {
      navigateToUser();
    } else {
      Message.showError(context: context, message: response.error.message);
    }
  }

  void navigateToUser() {
    Navigator.pushAndRemoveUntil(
      context,
      MaterialPageRoute(builder: (context) => UserPage()),
          (Route<dynamic> route) => false,
    );
  }

  void navigateToSignUp() {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => SignUpPage()),
    );
  }

  void navigateToResetPassword() {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => ResetPasswordPage()),
    );
  }
}

主页:

class UserPage extends StatelessWidget {
  ParseUser currentUser;

  Future<ParseUser> getUser() async {
    currentUser = await ParseUser.currentUser() as ParseUser;
    return currentUser;
  }

  @override
  Widget build(BuildContext context) {
    void doUserLogout() async {
      var response = await currentUser.logout();
      if (response.success) {
        Message.showSuccess(
            context: context,
            message: 'User was successfully logout!',
            onPressed: () {
              Navigator.pushAndRemoveUntil(
                context,
                MaterialPageRoute(builder: (context) => LoginPage()),
                    (Route<dynamic> route) => false,
              );
            });
      } else {
        Message.showError(context: context, message: response.error.message);
      }
    }

    return Scaffold(
        appBar: AppBar(
          title: Text('User logged in - Current User'),
        ),
        body: FutureBuilder<ParseUser>(
            future: getUser(),
            builder: (context, snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                case ConnectionState.waiting:
                  return Center(
                    child: Container(
                        width: 100,
                        height: 100,
                        child: CircularProgressIndicator()),
                  );
                  break;
                default:
                  return Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Center(child: Text('Hello, ${snapshot.data.username}')),
                        SizedBox(
                          height: 16,
                        ),
                        Container(
                          height: 50,
                          child: ElevatedButton(
                            child: const Text('Logout'),
                            onPressed: () => doUserLogout(),
                          ),
                        ),
                      ],
                    ),
                  );
              }
            }));
  }
}

使用该应用程序时,登录工作正常,但当我重新加载该应用程序时,它只是“MyApp”中的“ParseServer.currentUser()” class returns null 并将我发送到登录屏幕。如果有人知道我做错了什么,我将不胜感激。

“MyApp”中的 FutureBuilder class 调用 Future 两次,我不确定为什么以及是否可能与此有关。

对于主要 Future 构建器的每个状态,将重新创建下面的所有小部件,将再次调用构建函数,并将再次调用 Future.Builder 中的函数。

您可以使用 AsyncMemoizer 来避免它。 AsyncMemoizer 将使 Future 仅被调用一次。 你有很多方法可以解决这个问题。 例如,您可以使用 StatefullWidget 并在 initState() 上获取数据,它只会被调用一次,即使父级重建,状态也会保持不变。

最好的做法是创建其他层来获取您的数据,而您的视图只负责显示,而不是获取数据。

https://pub.dev/packages/async

https://pub.dev/documentation/async/latest/async/AsyncMemoizer-class.html