我的第一个屏幕是登录屏幕,它需要检查用户是否已登录才能直接打开主屏幕,但是使用此检查却出现错误。
我正在检查initState,条件返回的是true,所以看起来问题出在导航器上。
如果用户已登录,跳过第一屏的正确方法是什么?
错误:
I/flutter (20803): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ I/flutter (20803): The following assertion was thrown building Navigator-[GlobalObjectKey<NavigatorState> I/flutter (20803): _WidgetsAppState#8ce27](dirty, state: NavigatorState#db484(tickers: tracking 2 tickers)): I/flutter (20803): 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 2106 pos 12: '!_debugLocked': I/flutter (20803): is not true. I/flutter (20803): Either the assertion indicates an error in the framework itself, or we should provide substantially I/flutter (20803): more information in this error message to help you determine and fix the underlying cause.
码:
class LoginScreen extends StatefulWidget { @override _LoginScreenState createState() => _LoginScreenState(); } class _LoginScreenState extends State<LoginScreen> { final _emailController = TextEditingController(); final _passController = TextEditingController(); final _formKey = GlobalKey<FormState>(); final _scaffoldKey = GlobalKey<ScaffoldState>(); @override void initState() { super.initState(); if(FirebaseAuth.instance.currentUser() != null){ Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => HomeScreen() )); } } @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, body: ScopedModelDescendant<UserModel>( builder: (context, child, model){ if(model.isLoading) return Center( child: CircularProgressIndicator(), ); return Form( key: _formKey, child: ListView( padding: EdgeInsets.all(16), children: <Widget>[ SizedBox(height: 67), Icon(Icons.chrome_reader_mode, size: 150, color: Colors.blue,), SizedBox(height: 16,), TextFormField( controller: _emailController, decoration: InputDecoration( hintText: "Digite seu e-mail", border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), ), fillColor: Colors.blueAccent ), keyboardType: TextInputType.emailAddress, validator: (text){ if(text.isEmpty || !text.contains("@")) return "E-mail inválido!"; }, ), SizedBox(height: 16,), TextFormField( controller: _passController, decoration: InputDecoration( hintText: "Digite sua senha", border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), ), fillColor: Colors.blueAccent ), obscureText: true, validator: (text){ if(text.isEmpty || text.length < 6) return "Digite a senha!"; }, ), SizedBox(height: 16,), FlatButton( padding: EdgeInsets.all(13), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10) ), color: Colors.blue, child: Text("Entrar", style: TextStyle( color: Colors.white, fontSize: 20 ), ), onPressed: (){ if(_formKey.currentState.validate()){ model.signIn( email: _emailController.text, pass: _passController.text, onSuccess: _onSuccess, onFail: _onFail, ); } }, ), SizedBox(height: 10,), InkWell( onTap: (){ if(_emailController.text.isEmpty || !_emailController.text.contains("@")){ _scaffoldKey.currentState.showSnackBar( SnackBar(content: Text("Insira um e-mail válido para recuperação", style: TextStyle(fontSize: 14), ), backgroundColor: Colors.redAccent, duration: Duration(seconds: 3), ) ); } else { model.recoverPass(_emailController.text); _scaffoldKey.currentState.showSnackBar( SnackBar( content: Text("O e-mail de recuperação foi enviado!", style: TextStyle(fontSize: 14), ), backgroundColor: Colors.green, duration: Duration(seconds: 3), ) ); } }, child: Text("Esqueci minha senha", style: TextStyle( color: Colors.black, fontSize: 16, fontWeight: FontWeight.w400 ), textAlign: TextAlign.center, ), ), SizedBox(height: 30,), InkWell( onTap: (){ Navigator.of(context).push(MaterialPageRoute( builder: (context)=> SignUpScreen()) ); }, child: Text("Não tem conta? Cadastre-se!", style: TextStyle( color: Colors.black, fontSize: 16, fontWeight: FontWeight.w600 ), textAlign: TextAlign.center, ), ), ], ), ); }, ), ); } }
好了,您可以使用另一种方法解决此类问题。而是检查您的loginScreen类中是否有用户登录,您可以在此之前执行此步骤,然后决定是否有用户登录时是否显示loginScreen或显示另一个屏幕,我想是MainScreen,如果该用户已登录。 。
我将简要介绍如何完成此操作。希望对您有所帮助。但是在我向您解释源代码中有什么问题之前。
if(FirebaseAuth.instance.currentUser() != null){ // wrong call in wrong place! Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => HomeScreen() )); }
您的代码已损坏,因为它currentUser()是一个异步函数,并且在您进行调用时,此函数将返回一个不完整的Future对象,该对象是一个非null的对象。因此,导航pushReplacement 器始终被调用,并且由于小部件的状态尚未就绪而崩溃。
currentUser()
pushReplacement
作为解决方案,您可以使用FutureBuilder并确定将打开哪个屏幕。
int main(){ runApp( YourApp() ) } class YourApp extends StatelessWidget{ @override Widget build(BuildContext context){ return FutureBuilder<FirebaseUser>( future: FirebaseAuth.instance.currentUser(), builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot){ if (snapshot.hasData){ FirebaseUser user = snapshot.data; // this is your user instance /// is because there is user already logged return MainScreen(); } /// other way there is no user logged. return LoginScreen(); } ); } }
使用这种方法可以避免LoginScreen类来验证是否有用户登录!
建议您可以将snapshot.connectionState属性与一起使用,switch case以实现更精细的控件。
snapshot.connectionState
switch case