- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我使用我的应用程序jwt认证。我有带有块模式的主页,该页面选择要在屏幕上加载页面的页面(LoginScreen或AppScreen)。 LoginScreen有自己的块模式,也有AppScreen。
当我输入登录名和密码并单击登录时,将调度LoginEvent,该请求将请求发送到Web服务并获得带有jwt token 的响应,该 token 将存储在共享首选项中,但与此同时,AppScreen会用其bloc呈现。 AppScreen的时间块正在发送数据请求(需要jwt token ),但会为null,因为尚未存储jwt token 。我发现一种解决方法不是一种优雅的方法,也可以使用延迟,但这不是正确的方法...
解决AppScreen:
@override
void initState() {
super.initState();
_bloc = BottomNavigationBloc(workoutTypeRepository: WorkoutTypeRepository());
_bloc.add(AppScreenLunched());
_bloc.add(AppScreenLunched());
}
_bloc.add(AppScreenLunched());
数据无法加载到Homepage,因为它从Web服务接收到null
_bloc.add(AppScreenLunched());
_bloc.add(AppScreenLunched());
add
数据为空
add
我最终获得了随bloc提供给主页的数据
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
AuthBloc _authBloc;
LoginRepository _loginRepository;
@override
void initState() {
super.initState();
_loginRepository = LoginRepository();
_authBloc = AuthBloc(loginRepository: _loginRepository);
_authBloc.add(AppStarted());
}
@override
void dispose() {
super.dispose();
_authBloc.close();
}
@override
Widget build(BuildContext context) {
return BlocProvider<AuthBloc>(
create: (_) => _authBloc,
child: MaterialApp(
title: 'TEST',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocBuilder(
bloc: _authBloc,
builder: (BuildContext context, AuthState state) {
if (state is AuthUninitialized) {
return LoginPage(loginRepository: _loginRepository);
} else if (state is AuthAuthenticated) {
return AppScreen();
} else if (state is AuthUnauthenticated) {
return LoginPage(loginRepository: _loginRepository);
} else if (state is AuthLoading) {
return LoadingIndicator();
}
return LoginPage(loginRepository: _loginRepository);
}
)
)
);
}
}
class LoginForm extends StatefulWidget {
@override
_LoginFormState createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
final registerRepository = RegisterRepository();
LoginBloc _loginBloc;
@override
void initState() {
super.initState();
_loginBloc = BlocProvider.of<LoginBloc>(context);
}
@override
void dispose() {
super.dispose();
_loginBloc.close();
}
@override
Widget build(BuildContext context) {
_onLoginButtonPressed() {
_loginBloc.add(LoginButtonPressed(
email: _emailController.text,
password: _passwordController.text,
));
}
class AppScreen extends StatefulWidget {
@override
_AppScreenState createState() => _AppScreenState();
}
class _AppScreenState extends State<AppScreen> {
BottomNavigationBloc _bloc;
@override
void initState() {
super.initState();
_bloc = BottomNavigationBloc(workoutTypeRepository: WorkoutTypeRepository());
_bloc.add(AppScreenLunched());
_bloc.add(AppScreenLunched());
}
@override
void dispose() {
super.dispose();
_bloc.close();
}
@override
Widget build(BuildContext context) {
return BlocProvider<BottomNavigationBloc>(
create: (_) => _bloc,
child: BlocBuilder(
bloc: _bloc,
builder: (BuildContext context, BottomNavigationState state) {
return Scaffold(
appBar: AppBar(
title: Text('TEST'),
),
body: _blocBuilder(context, state),
bottomNavigationBar: BottomActionBar(),
);
},
),
);
}
Widget _blocBuilder(BuildContext context, BottomNavigationState state) {
if (state is PageLoading) {
return Center(child: CircularProgressIndicator());
} else if (state is HomePageLoaded) {
return HomePage(workoutTypes: state.workoutTypes);
} else if (state is SearchPageLoaded) {
return Center(child: Text("SearchPage"));
// return SearchPage();
} else if (state is WorkoutPageLoaded) {
// return Center(child: Text("WorkoutPage"));
return WorkoutPage();
} else if (state is FavoritePageLoaded) {
return Center(child: Text("FavoritePage"));
// return SearchPage();
} else if (state is ProfilePageLoaded) {
return Center(child: Text("ProfilePage"));
// return ProfilePage();
}
return Container();
}
}
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final LoginRepository loginRepository;
AuthBloc({@required this.loginRepository}) : assert(loginRepository != null);
@override
AuthState get initialState => AuthUninitialized();
@override
Stream<AuthState> mapEventToState(
AuthEvent event,
) async* {
if (event is AppStarted) {
final bool hasToken = await loginRepository.hasToken();
if (hasToken) {
yield AuthAuthenticated();
} else {
yield AuthUnauthenticated();
}
}
if (event is LoggedIn) {
final bool hasToken = await loginRepository.hasToken();
if (hasToken) {
yield AuthAuthenticated();
} else {
yield AuthUnauthenticated();
}
}
if (event is LoggedOut) {
yield AuthLoading();
await loginRepository.deleteToken();
yield AuthUnauthenticated();
}
}
}
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final LoginRepository loginRepository;
final AuthBloc authBloc;
LoginBloc({
@required this.loginRepository,
@required this.authBloc,
}) : assert(loginRepository != null),
assert(authBloc != null);
LoginState get initialState => LoginInitial();
@override
Stream<LoginState> mapEventToState(LoginEvent event) async* {
if (event is LoginButtonPressed) {
yield LoginLoading();
try {
await loginRepository.authenticate(
email: event.email,
password: event.password,
);
authBloc.add(LoggedIn());
yield LoginInitial();
} catch (error) {
yield LoginFailure(error: error.toString());
}
}
}
}
class BottomNavigationBloc extends Bloc<BottomNavigationEvent, BottomNavigationState> {
int currentIndex = 0;
final WorkoutTypeRepository workoutTypeRepository;
BottomNavigationBloc({this.workoutTypeRepository}) : assert(workoutTypeRepository != null);
@override
BottomNavigationState get initialState => PageLoading();
@override
Stream<BottomNavigationState> mapEventToState(BottomNavigationEvent event) async* {
if (event is AppScreenLunched) {
this.add(PageTapped(index: this.currentIndex));
}
if (event is PageTapped) {
this.currentIndex = event.index;
yield CurrentIndexChanged(currentIndex: this.currentIndex);
yield PageLoading();
if (this.currentIndex == 0) {
final workoutTypes = await getWorkoutType();
yield HomePageLoaded(workoutTypes: workoutTypes);
}
if (this.currentIndex == 1) {
yield SearchPageLoaded();
}
if (this.currentIndex == 2) {
yield WorkoutPageLoaded();
}
if (this.currentIndex == 3) {
yield FavoritePageLoaded();
}
if (this.currentIndex == 4) {
yield ProfilePageLoaded();
}
}
}
Future<List<WorkoutType>> getWorkoutType() async {
List<WorkoutType> workoutType = await workoutTypeRepository.getWorkoutType();
return workoutType;
}
}
最佳答案
主页:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
AuthBloc _authBloc;
LoginRepository _loginRepository;
@override
void initState() {
super.initState();
_loginRepository = LoginRepository();
_authBloc = AuthBloc(loginRepository: _loginRepository);
_authBloc.add(AppStarted());
}
@override
void dispose() {
super.dispose();
_authBloc.close();
}
@override
Widget build(BuildContext context) {
return BlocProvider<AuthBloc>(
create: (context) => _authBloc,
child: MaterialApp(
title: 'TEST',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocBuilder(
bloc: _authBloc,
builder: (BuildContext context, AuthState state) {
if (state is AuthUninitialized) {
return LoadingIndicator();
// return LoginPage(loginRepository: _loginRepository);
} else if (state is AuthAuthenticated) {
return AppScreen();
} else if (state is AuthUnauthenticated) {
return LoginPage(loginRepository: _loginRepository);
} else if (state is AuthLoading) {
return LoadingIndicator();
}
return LoginPage(loginRepository: _loginRepository);
}
)
)
);
}
}
class LoginPage extends StatelessWidget {
final LoginRepository loginRepository;
LoginPage({
Key key,
@required this.loginRepository
}) : assert(loginRepository != null), super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider(
create: (context) {
return LoginBloc(
loginRepository: loginRepository,
authBloc: BlocProvider.of<AuthBloc>(context)
);
},
child: Stack(
children: <Widget>[
new Container(
decoration: BoxDecoration(
image: backgroundImage
)
),
new Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
LoginForm()
]
),
),
)
],
),
)
);
}
}
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final LoginRepository loginRepository;
AuthBloc({@required this.loginRepository}) : assert(loginRepository != null);
@override
AuthState get initialState => AuthUninitialized();
@override
Stream<AuthState> mapEventToState(
AuthEvent event,
) async* {
if (event is AppStarted) {
final bool hasToken = await loginRepository.hasToken();
if (hasToken) {
yield AuthAuthenticated();
} else {
yield AuthUnauthenticated();
}
}
if (event is LoggedIn) {
final bool hasToken = await loginRepository.hasToken();
if (hasToken) {
yield AuthAuthenticated();
} else {
yield AuthUnauthenticated();
}
}
if (event is LoggedOut) {
yield AuthLoading();
await loginRepository.deleteToken();
yield AuthUnauthenticated();
}
}
}
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final LoginRepository loginRepository;
final AuthBloc authBloc;
LoginBloc({
@required this.loginRepository,
@required this.authBloc,
}) : assert(loginRepository != null),
assert(authBloc != null);
LoginState get initialState => LoginInitial();
@override
Stream<LoginState> mapEventToState(LoginEvent event) async* {
if (event is LoginButtonPressed) {
yield LoginLoading();
try {
await loginRepository.authenticate(
email: event.email,
password: event.password,
);
authBloc.add(LoggedIn());
yield LoginInitial();
} catch (error) {
yield LoginFailure(error: error.toString());
}
}
}
}
class LoginRepository {
LoginProvider _loginProvider;
LoginRepository({LoginProvider loginProvider}) {
_loginProvider = loginProvider ?? LoginProvider();
}
Future<String> authenticate({String email, String password}) async {
if (email == null || password == null) {
return "Nie podanu loginu lub hasła";
}
var loginData =
await _loginProvider.login(email: email, password: password);
var token = AuthToken.fromJson(loginData);
return token.accessToken;
}
Future<bool> hasToken() async {
String token = await LocalStorage.get(Constant.ACCESS_TOKEN);
if (token != null) {
return true;
}
return false;
}
Future<void> persistToken(String token) async {
if (token != null) {
await LocalStorage.save(Constant.ACCESS_TOKEN, "${Constant.TOKEN_TYPE_BEARER} $token");
}
}
Future<void> deleteToken() async {
await LocalStorage.remove(Constant.ACCESS_TOKEN);
}
}
class LocalStorage {
static save(String key, String value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(key, value);
}
static Future<String> get(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.get(key);
}
static remove(String key) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove(key);
}
static removeAll() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var keys = prefs.getKeys();
keys.map((key) {
remove(key);
});
}
}
关于flutter - Flutter:子 block 正在初始化,但是数据尚未存储在shared_preferences中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59111719/
我正在尝试从flutter应用程序构建apk,但出现此错误: Note: /mnt/Software/Linux/Flutter/flutter/.pub-cache/hosted/pub.dartl
我有一个名为 X 的较大应用程序,还有另一个名为 Y 的较小应用程序。他们现在彼此分开,并且工作正常。我想将应用程序 Y 集成到 X 中。我想将 Y 的代码放入 X 项目中,但它们应该有不同的 Mai
在android Studio中选择Create New Flutter Project,出现如下4个选项。 Flutter 应用程序 Flutter 插件 Flutter 包 flutter 模块
我看到我的 flutter 项目生成了一个文件 ios/Flutter/Flutter.podspec ,这个文件有什么用? 如果它与生成的 Flutter.framework 有关? 我应该将它包含
我尝试过的 在包含flutter SDK的位置添加/编辑.bash_profile.rtf文件。 导出PATH = / Users / temur / Documents / Projects / F
Flutter 日志会打印数千个详细/垃圾邮件日志。 我正在尝试调试一个复杂的应用程序,但是打印太冗长了,以至于我很难找到我自己打印的东西。 有没有办法禁用详细? 就像是: Logger.level.
在flutter 1.22更新之后,我在Lineargradient colors属性中遇到错误,这给我一个错误,即未定义名称colors参数。.在Android中更新flutter和flutter插
在下面的代码 widget.hintText 中给出错误,我试图将日期选择器作为单独的组件,并在从其他文件调用它时动态传递提示文本值。 import 'package:date_field/date_
在下面的代码 widget.hintText 中给出错误,我试图将日期选择器作为单独的组件,并在从其他文件调用它时动态传递提示文本值。 import 'package:date_field/date_
Flutter 1.0 发布后,我正在按照步骤搭建 Flutter 开发环境。 在步骤中(如所附屏幕截图所示),它说要更新 $PATH 两次,一次使用 flutter 工具的路径 export PAT
我有一个用 flutter 编写的移动应用程序,我想将其转换为 flutter_web 应用程序(集成 flutter_web 尚不可用)。我目前遇到包裹问题。 我已按照本网站中列出的说明进行操作 h
如何向我的 Flutter 路由添加自定义转换?这是我目前的路线结构。 class MyApp extends StatelessWidget { // This widget is the
我正在尝试通过 URL 在 webview 中显示网页。我试过 flutter_webview_plugin 插件,但是当我在浏览器上运行项目时它不起作用。 在 flutter web applica
我正在使用 animatedContainer 在按下按钮时显示 listView.builder()。这是一个要显示的简单子(monad)列表,但问题是我不知道 ListView 构建器的高度会传递
我目前正在我的应用程序中制作渐变背景动画......我正在使用 lottie 动画的帮助下这样做!我试图将它封装在一个容器中并成功地做到了。但是有一个问题,尽管我将高度更改为大于 2000 的东西,但
美好的一天! 我无法弄清楚如何使用 google 标签管理器设置 flutter。我找到了 this package包括标签管理器 api。但是我不知道如何正确配置它。 (在网络上我只需要复制粘贴一个
我的购物车模型如下 class Cart { String description; double unitCost; double amount; int quantity; S
在 Flutter 应用程序中,我想为在线托管的资源(图像、视频等)实现缓存。 我希望它能在原生平台 (Android/iOS)(例如使用文件系统)和网络(例如使用 IndexedDB)上运行。 Fl
我写了一个页面,在顶部一切都很好,应该是这样。在底部我有一个事件的历史。我的容器的宽度是自动确定的(取决于屏幕的宽度),而高度 - 不,在不同的设备上有不同的高度(底部的缩进是不同的)。是否可以自动确
我正在处理一个页面,其中有一些字段,例如 textfield 和 slider。在页面的末尾必须有一个用于进行下一步的按钮,该按钮被包裹在 Align 中以在页面之间具有固定位置。 另一方面,resi
我是一名优秀的程序员,十分优秀!