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

Posted

技术标签:

【中文标题】Flutter/dart:Parse Server sdk:ParseUser.currentUser() 函数在重置时返回 null【英文标题】:Flutter/dart: Parse Server sdk: ParseUser.currentUser() function returning null on reset 【发布时间】:2021-03-25 22:06:16 【问题描述】:

我在我的颤振应用程序中使用“Parse Server sdk”和“back4app”作为后端,并且在使用以下函数调用当前用户时遇到问题:“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,
                  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()”返回 null 并将我发送到登录屏幕。如果有人知道我做错了什么,我将不胜感激。

“MyApp”类中的 FutureBuilder 也两次调用 Future 我不知道为什么,如果这可能与它有关。

【问题讨论】:

【参考方案1】:

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

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

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

https://pub.dev/packages/async

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

【讨论】:

以上是关于Flutter/dart:Parse Server sdk:ParseUser.currentUser() 函数在重置时返回 null的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter(Dart)中将字符串解析为 DateTime [重复]

flutter Dart语言List如何获取索引值

颤振无法导入`flutter_webrtc.dart`

Flutter - dart.ui 没有方法'platformViewRegistry'

不会Dart,还搞什么Flutter?

Flutter——实操踩坑:升级Flutter dart