dart - 如何检查用户是否已登录,如果已登录则显示其他屏幕?
问题描述
我的第一个屏幕是登录屏幕,它需要检查用户是否登录才能直接打开主屏幕,但使用此检查时出现错误。
我正在检查 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 对象,该对象是一个非空对象。所以导航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
带有 a 的属性switch case
来实现更精细的控制。
推荐阅读
- android - 我如何传递一个列表
- > 到我的片段?
- sql - SQL Extended Events Capture Truncate Statements
- permissions - i have working on putty in my window machine ussing ubuntu
- google-chrome - Is there any way to stop websites from detecting your installed extensions?
- python - Calling a Python function on each entry of a text file
- javascript - How to create login page on chrome extension?
- sql - 计算每月重置的每天不同的值(大查询)
- api - 在邮递员测试中访问完整的响应大小?
- arrays - Solved: Impossible to pass a Motif widget array as client_data in XtAddCallback?
- swift - 复杂的 CoreImage CIFilter 管道递归地消耗 GB 的内存