Flutter状态管理Bloc之登录示例

 更新时间:2022年03月24日 10:35:11   作者:mazaiting  
这篇文章主要为大家详细介绍了Flutter状态管理Bloc之登录示例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Flutter状态管理Bloc之登录的具体代码,供大家参考,具体内容如下

1. 依赖

dependencies:
  flutter_bloc: ^2.1.1
  equatable: ^1.0.1

2. UserRepository 用于管理用户数据

提供认证方法,删除Token,保存Token,是否包含Token四个方法。

import 'package:flutter/material.dart';
 
/// 用户数据仓库
class UserRepository {
 
  /// 认证
  /// @param username 用户名
  /// @param password 密码
  /// @return 返回认证信息
  Future<String> authenticate({
    @required String username,
    @required String password,
  }) async {
    await Future.delayed(Duration(seconds: 1));
    return "token";
  }
 
  /// 删除Token
  Future<void> deleteToToken() async {
    await Future.delayed(Duration(seconds: 1));
    return ;
  }
 
  /// 保存Token
  /// @param token 令牌
  Future<void> persistToken(String token) async {
    // 保存
    await Future.delayed(Duration(seconds: 1));
    return ;
  }
 
  /// 判断是否有Token
  /// @return true: 有; false: 没有Token
  Future<bool> hasToken() async {
    // 读取Token
    await Future.delayed(Duration(seconds: 1));
    return false;
  }
}

3. AuthenticateState

  • uninitialized - 身份验证未初始化
  • loading - 等待保存/删除Token
  • authenticated - 认证成功
  • unauthenticated - 未认证
import 'package:equatable/equatable.dart';
 
/// 认证状态
abstract class AuthenticationState extends Equatable {
  @override
  List<Object> get props => [];
}
 
/// - uninitialized - 身份验证未初始化
class AuthenticationUninitialized extends AuthenticationState {}
/// - loading - 等待保存/删除Token
class AuthenticationLoading extends AuthenticationState {}
/// - authenticated - 认证成功
class AuthenticationAuthenticated extends AuthenticationState {}
/// - unauthenticated - 未认证
class AuthenticationUnauthenticated extends AuthenticationState {}

4. 认证事件

  • AppStarted - App 启动事件
  • LoggedIn - 登录事件
  • LoggedOut - 退出登录事件
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
 
/// 认证事件
abstract class AuthenticationEvent extends Equatable {
 
  const AuthenticationEvent();
 
  @override
  List<Object> get props => [];
 
}
 
/// APP 启动事件
class AppStart extends AuthenticationEvent {}
 
/// APP 登录事件
class LoginIn extends AuthenticationEvent {
  
  final String token;
 
  const LoginIn({@required this.token});
 
  @override
  List<Object> get props => [token];
 
  @override
  String toString() => "LoggedIn { token: $token }";
}
 
/// APP 退出登录事件
class LoginOut extends AuthenticationEvent {}

5. AuthenticationBloc

  • 实现构造方法
  • 实现initialState方法
  • 实现mapEventToState方法
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import './bloc.dart';
import 'package:state_manage/login/user_repository.dart';
 
/// 认证Bloc
class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState> {
  // 用户仓库
  final UserRepository userRepository;
 
  AuthenticationBloc({@required this.userRepository}): assert(userRepository != null);
 
  @override
  AuthenticationState get initialState => AuthenticationUninitialized();
 
  @override
  Stream<AuthenticationState> mapEventToState(AuthenticationEvent event) async* {
    if (event is AppStarted) {
      // 判断是否有Token
      final bool hasToken = await userRepository.hasToken();
      if (hasToken) {
        yield AuthenticationAuthenticated();
      } else {
        yield AuthenticationUnauthenticated();
      }
    } else if (event is LoggedIn) {
      yield AuthenticationLoading();
      await userRepository.persistToken(event.token);
      yield AuthenticationAuthenticated();
    } else if (event is LoggedOut) {
      yield AuthenticationLoading();
      await userRepository.deleteToToken();
      yield AuthenticationUnauthenticated();
    }
  }
}

6. SplashPage 启动页

import 'package:flutter/material.dart';
 
/// 启动页
class SplashPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('Splash Screen'),
      ),
    );
  }
}

7. HomePage 主页

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:state_manage/login/bloc/bloc.dart';
 
/// 主页
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Container(
        child: Center(
          child: RaisedButton(
            child: Text('logout'),
            onPressed: () => BlocProvider.of<AuthenticationBloc>(context).add(LoggedOut())
          ),
        ),
      ),
    );
  }
}

8. LoginState 登录状态

  • LoginInitial - 初始化状态
  • LoginLoading - 登录中状态
  • LoginFailure - 登录失败状态
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
 
/// 登录状态
@immutable
abstract class LoginState extends Equatable {
  const LoginState();
 
  @override
  List<Object> get props => [];
}
  
/// 登录初始化状态
class LoginInitial extends LoginState {}
 
/// 正在登录中状态
class LoginLoading extends LoginState {}
 
/// 登录失败状态
class LoginFailure extends LoginState {
  final String error;
 
  const LoginFailure({@required this.error});
 
  @override
  List<Object> get props => [error];
 
  @override
  String toString() => "LoginFailure { error: $error }";
}

9. LoginEvent 登录事件

import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
 
/// 登录事件
@immutable
abstract class LoginEvent extends Equatable{}
 
/// 登录事件
class LoginPressed extends LoginEvent {
  /// 用户名
  final String username;
  /// 密码
  final String password;
 
  LoginPressed({
    @required this.username,
    @required this.password
  });
 
  @override
  List<Object> get props => [username, password];
 
  @override
  String toString() => "LoginPressed { username: $username, password: $password }";
}

10. LoginBloc 实现

import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:state_manage/login/user_repository.dart';
import './bloc.dart';
 
class LoginBloc extends Bloc<LoginEvent, LoginState> {
  /// 用户信息仓库
  final UserRepository userRepository;
 
  /// 认证Bloc
  final AuthenticationBloc authenticationBloc;
 
  LoginBloc({@required this.userRepository, @required this.authenticationBloc})
      : assert(userRepository != null),
        assert(authenticationBloc != null);
 
  @override
  LoginState get initialState => LoginInitial();
 
  @override
  Stream<LoginState> mapEventToState(
    LoginEvent event,
  ) async* {
    if (event is LoginPressed) {
      yield LoginLoading();
 
      try {
        final token = await userRepository.authenticate(
          username: event.username,
          password: event.password
        );
        authenticationBloc.add(LoggedIn(token: token));
        yield LoginInitial();
      } catch (error) {
        yield LoginFailure(error: error);
      }
    }
  }
}

11. 登录页面

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:state_manage/login/bloc/bloc.dart';
import 'package:state_manage/login/user_repository.dart';
 
/// 登录页面
class LoginPage extends StatelessWidget {
  /// 用户信息仓库
  final UserRepository userRepository;
 
  LoginPage({Key key, @required this.userRepository})
      : assert(userRepository != null),
        super(key: key);
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login'),
      ),
      body: BlocProvider(
        create: (ctx) => LoginBloc(
            authenticationBloc: BlocProvider.of(context),
            userRepository: userRepository),
        child: LoginForm(),
      ),
    );
  }
}
 
/// 登录表单
class LoginForm extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _LoginFormState();
}
 
/// 登录状态表单
class _LoginFormState extends State<LoginForm> {
  /// 用户名控制器
  final _usernameController = TextEditingController();
 
  /// 密码控制器
  final _passwordController = TextEditingController();
  @override
  Widget build(BuildContext context) {
    _onLoginPressed() {
      BlocProvider.of<LoginBloc>(context).add(LoginPressed(
          username: _usernameController.text,
          password: _passwordController.text));
    }
 
    return BlocListener<LoginBloc, LoginState>(
      listener: (ctx, state) {
        if (state is LoginFailure) {
          Scaffold.of(context).showSnackBar(SnackBar(
            content: Text('${state.error}'),
            backgroundColor: Colors.red,
          ));
        }
      },
      child: BlocBuilder<LoginBloc, LoginState>(
        builder: (ctx, state) {
          return Form(
            child: Column(
              children: <Widget>[
                TextFormField(
                  decoration: InputDecoration(labelText: 'username'),
                  controller: _usernameController,
                ),
                TextFormField(
                  decoration: InputDecoration(labelText: 'password'),
                  controller: _passwordController,
                ),
                RaisedButton(
                  onPressed: state is LoginLoading ? _onLoginPressed : null,
                  child: Text('Login'),
                ),
                Container(
                  child: state is LoginLoading
                      ? CircularProgressIndicator()
                      : null,
                )
              ],
            ),
          );
        },
      ),
    );
  }
}

12. 测试页面

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:state_manage/login/bloc/bloc.dart';
import 'package:state_manage/login/home_page.dart';
import 'package:state_manage/login/login_page.dart';
import 'package:state_manage/login/splash_page.dart';
import 'package:state_manage/login/user_repository.dart';
 
/// 登录测试页面
class LoginTest extends StatelessWidget {
  // 数据仓库
  final userRepository = UserRepository();
 
  @override
  Widget build(BuildContext context) {
    return BlocProvider<AuthenticationBloc>(
      create: (context) =>
          AuthenticationBloc(userRepository: userRepository)..add(AppStarted()),
      child: App(userRepository: userRepository),
    );
  }
}
 
/// 应用页
class App extends StatelessWidget{
  // 数据仓库
  final UserRepository userRepository;
 
  App({Key key, @required this.userRepository}) : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (context, state) {
          if (state is AuthenticationAuthenticated) {
            return HomePage();
          } else if (state is AuthenticationUnauthenticated) {
            return LoginPage(userRepository: userRepository);
          } else if (state is AuthenticationLoading) {
            return LoadingIndicator();
          } else {
            if (state is AuthenticationUninitialized) {
              return SplashPage();
            } else {
              return SplashPage();
            }
          }
        },
      ),
    );
  }
 
}
 
/// 加载状态
class LoadingIndicator extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Center(
        child: CircularProgressIndicator(),
      ),
    );
  }
}

效果图:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Android协程代替Handler使用示例详解

    Android协程代替Handler使用示例详解

    这篇文章主要为大家介绍了Android 协程代替Handler使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • Android性能优化及性能优化工具

    Android性能优化及性能优化工具

    这篇文章主要给大家分享的是Android性能优化及性能优化工具,下面文字会围绕Android性能优化的相关资料详细的展开具体内容,需要的朋友可以参考一下,希望对大家有所帮助
    2021-11-11
  • Android App中使用SurfaceView制作多线程动画的实例讲解

    Android App中使用SurfaceView制作多线程动画的实例讲解

    这篇文章主要介绍了Android App中使用SurfaceView制作多线程动画的实例讲解,SurfaceView经常被用来制作游戏中的动画,不过同时要注意画面闪烁的问题,需要的朋友可以参考下
    2016-04-04
  • Android实现带签到赢积分功能的日历

    Android实现带签到赢积分功能的日历

    这篇文章主要为大家详细介绍了Android实现带签到赢积分功能的日历,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • Android开发解决字符对齐问题方法

    Android开发解决字符对齐问题方法

    这篇文章主要为大家介绍了Android开发解决字符对齐问题方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Android开发自学笔记(五):使用代码控制界面

    Android开发自学笔记(五):使用代码控制界面

    这篇文章主要介绍了Android开发自学笔记(五):使用代码控制界面,本文讲解了添加第二个layout、添加MyActivity的code、setup函数、getResult函数等内容,需要的朋友可以参考下
    2015-04-04
  • Android ANR无响应分析解决方案

    Android ANR无响应分析解决方案

    这篇文章主要为大家介绍了Android ANR无响应分析解决方案,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Flutter 实现虎牙/斗鱼 弹幕功能

    Flutter 实现虎牙/斗鱼 弹幕功能

    这篇文章主要介绍了Flutter 实现虎牙/斗鱼 弹幕功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • Android快速分析apk工具aapt的使用教程

    Android快速分析apk工具aapt的使用教程

    这篇文章主要介绍了Android快速分析apk工具aapt的使用教程,本文讲解了什么是aapt、主要用法、使用aapt、查看apk的基本信息、查看基本信息、查看应用权限等内容,需要的朋友可以参考下
    2015-04-04
  • 浅析Android手机卫士接收短信指令执行相应操作

    浅析Android手机卫士接收短信指令执行相应操作

    通过广播接收者,接收到短信,对短信内容进行判断,如果为我们指定的值就执行相应的操作。本文给大家介绍Android手机卫士接收短信指令执行相应操作,感兴趣的朋友参考下吧
    2016-04-04

最新评论