Flutter/dart:Parse Server sdk:ParseUser.currentUser() 函数在重置时返回 null

问题描述

我在我的 Flutter 应用程序中使用带有“back4app”的“Parse Server sdk”作为后端,但我在应用程序初始启动时无法调用当前用户使用函数:“ParseUser.currentUser()”但是出于某种原因,即使在我重新启动应用程序时登录后,该函数也会返回 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,obscureText: true,labelText: 'Password'),Container(
                  height: 50,child: ElevatedButton(
                    child: const Text('Login'),onpressed: isLoggedIn ? null : () => doUserLogin(),child: ElevatedButton(
                    child: const Text('Sign Up'),onpressed: () => navigatetoSignUp(),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()),);
            });
      } 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(),snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                case ConnectionState.waiting:
                  return Center(
                    child: Container(
                        width: 100,);
                  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()”返回空值并将我发送到登录屏幕。如果有人知道我做错了什么,我将不胜感激。

“MyApp”类中的 FutureBuilder 也调用了 Future 两次,我不确定为什么以及这是否与它有关。

解决方法

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

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

最佳实践是创建其他层来获取您的数据,而您的视图只负责显示而不是获取它。

https://pub.dev/packages/async

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