亲宝软件园·资讯

展开

Flutter状态管理Bloc之登录

mazaiting 人气:0

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

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. 认证事件

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

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 登录状态

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(),
      ),
    );
  }
}

效果图:

加载全部内容

相关教程
猜你喜欢
用户评论