我正在使用Provider和应用程序中的流FirebaseAuth.instance.onAuthStateChanged来确定启动时重定向的位置,但是尽管用户已经登录(从以前的启动中),但该应用程序会在登录屏幕上启动,几乎1第二秒后重定向到主页,从第一分钟开始应从该主页开始。即使在飞行模式下也会发生这种情况。
我想知道是否有任何方法可以解决此问题,即使无法一次显示主屏幕,我也不知道如何区分未登录的用户(空->登录屏幕) )并加载用户(null->加载屏幕)。
一些代码:
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final FirebaseAuth _auth = FirebaseAuth.instance;
final DatabaseService db = DatabaseService();
@override
Widget build(BuildContext context) {
return StreamProvider<FirebaseUser>.value(
value: _auth.onAuthStateChanged,
child: Consumer<FirebaseUser>(
builder: (context, firebaseUser, child) {
return MultiProvider(
providers: [
if (firebaseUser != null)
ChangeNotifierProvider(create: (ctx) => CollectionState(firebaseUser)),
StreamProvider<List<Collection>>.value(value: db.streamCollections(firebaseUser)),
],
child: MaterialApp(
title: 'My App',
routes: {
'/': (ctx) => LandingPage(),
'/login': (ctx) => LoginPage(),
'/emailSignIn': (ctx) => EmailSignInPage(),
'/emailSignUp': (ctx) => EmailSignUpPage(),
'/emailUnverified': (ctx) => EmailUnverifiedPage(),
'/home': (ctx) => HomePage(),
'/settings': (ctx) => Settings(),
},
),
);
},
),
);
}
}
class LandingPage extends StatelessWidget {
final DatabaseService _db = DatabaseService();
@override
Widget build(BuildContext context) {
final user = Provider.of<FirebaseUser>(context);
final userCondition =
user == null ? 'null' : user.isEmailVerified ? 'verifiedUser' : 'unverifiedUser';
switch (userCondition) {
case 'null':
return LoginPage();
break;
case 'unverifiedUser':
return EmailUnverifiedPage();
break;
case 'verifiedUser':
return HomePage();
break;
}
}
}
代码略有简化,我只是将服务用于身份验证实例。
答案 0 :(得分:1)
我知道我已经很晚了,但是我遇到了同样的问题几周了,终于找到答案了。
@ChinkySight是正确的,他说最好使用StreamBuilder
,主要是因为您可以访问connectionState属性。
之所以存在延迟,是因为与流的连接未完全建立。因此,在ConnectionState.waiting期间,返回一个小部件,例如启动屏幕或只是一个容器。
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (_, snapshot) {
// Added this line
if (snapshot.connectionState == ConnectionState.waiting) {
return Container();
}
if (snapshot.data is FirebaseUser && snapshot.data != null) {
return HomePage();
}
return LoginPage();
});
}
}
您甚至可以使用Animated Switcher给返回语句添加精美的动画
return StreamBuilder(
stream: FirebaseAuth.instance.onAuthStateChanged,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
Widget widget;
if (snapshot.connectionState == ConnectionState.waiting) {
return Container();
}
switch (snapshot.hasData) {
case (true):
widget = HomePage();
break;
case (false):
widget = LoginPage();
}
return Stack(
children: <Widget>[
Scaffold(
backgroundColor: Colors.grey.shade200,
),
AnimatedSwitcher(
duration: Duration(milliseconds: 700),
child: FadeTransition(
opacity: animation,
child: widget,
),
);
},
)
],
);
},
);
答案 1 :(得分:1)
这适用于FlutterFire。
Firebase Auth使您可以通过以下方式实时订阅此状态 流。调用后,该流将立即提供 用户的当前身份验证状态,然后提供后续 身份验证状态更改时发生的事件。订阅 这些更改后,请在FirebaseAuth上调用authStateChanges()方法 实例:
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'package:flutter/material.dart';
import 'menu.dart';
import 'login.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MyApp()
);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitUp]);
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'TestApp',
theme: ThemeData(primarySwatch: Colors.blue),
home:
StreamBuilder<auth.User>(
stream: auth.FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<auth.User> snapshot) {
if(snapshot.hasData) {
print("data exists");
return HomePage();
}
else {
return LoginPage();
}
},
)
);
}
}
答案 2 :(得分:-1)
但是,尽管用户已经登录(以前的启动) 该应用程序在登录屏幕上启动,并在大约1秒后重定向 到主页,应该从第一个开始 片刻。
在这种情况下,最佳实践是使用包装器,该包装器将根据流FirebaseAuth.instance.onAuthStateChanged
说明:
您可能熟悉FirebaseAuth.instance.onAuthStateChanged
,当我们登录时会给出FirebaseUser
,而在没有登录时会给出null
。因此,基于此流,我将返回小部件。如果流提供的是FirebaseUser
而不是null
,这显然意味着用户已登录,则返回HomePage()
;否则,如果用户未登录,则只需返回{{1} }
因此,您不必担心已登录的用户,导航到LoginPage()
,然后在第二次重定向到LoginPage
之后。每当流中发生更改时,HomePage
都会重建(StreamBuilder
仅在执行登录或注销时更改)。如果用户退出
FirebaseAuth.instance.onAuthStateChanged
将自行重建并返回StreamBuilder
,因此您无需手动导航至LoginPage
。
LoginPage