Flutter Bloc - 事件不重新创建页面

时间:2021-02-23 16:08:44

标签: flutter flutter-bloc

我有一个简单的应用程序可以处理登录,这只是了解 Bloc 的工作原理以及如何管理状态的练习。
我遇到了 bloc 问题,由于某种原因,在添加事件后,它不会重建小部件树。

我有 3 个区块:

  1. 身份验证
  2. 登录
  3. 注册

Authentication 应该管理当前用户的状态并检查它是否存在令牌并显示 home
Login 应管理登录页面并在用户尝试登录并将其重定向到主页时做出响应。
Registration 应管理注册过程并将用户重定向到主页。

登录有效,我可以模拟登录并在用户重定向到主页后。
是注册的问题,注册后UI不更新,老是看注册表。

main.dart:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'bloc/registration/registration_bloc.dart';
import 'screens/home/home_screen.dart';
import 'screens/login/login_screen.dart';

import 'repositories/interfaces/authentication.dart';
import 'repositories/rest/authentication.dart';

import 'bloc/authentication/authentication_bloc.dart';

import 'routes.dart';
import 'theme.dart';

void main() {
  runApp(
    MultiRepositoryProvider(
      providers: [
        RepositoryProvider<AuthenticationRepository>(
          create: (context) {
            return RestAuthenticationProvider();
          },
        ),
      ],
      child: MultiBlocProvider(
        providers: [
          BlocProvider<AuthenticationBloc>(
            create: (context) {
              final authService = context.read<AuthenticationRepository>();
              return AuthenticationBloc(authService)..add(AppLoaded());
            },
          ),
        ],
        child: MyApp(),
      ),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: themeData,
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (context, state) {
          if (state is AuthenticationAuthenticated) {
            return HomeScreen();
          }
          return LoginScreen();
        },
      ),
      onGenerateRoute: RouteGenerator.generateRoute,
    );
  }
}

routes.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import 'screens/home/home_screen.dart';
import 'screens/login/login_screen.dart';
import 'screens/register/register_screen.dart';

class RouteGenerator {
  static const String loginScreen = '/login';
  static const String registerScreen = '/register';
  static const String homeScreen = '/home';

  RouteGenerator._();

  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case loginScreen:
        {
          return MaterialPageRoute(
            builder: (_) {
              return LoginScreen();
            },
          );
        }
      case registerScreen:
        {
          return MaterialPageRoute(
            builder: (_) {
              return RegisterScreen();
            },
          );
        }
      case homeScreen:
        {
          return MaterialPageRoute(
            builder: (_) {
              return HomeScreen();
            },
          );
        }
      /* case singlePermissionPage:
        {
          final SinglePermissionRequestArguments permissionRequestArguments =
              settings.arguments;
          return MaterialPageRoute(
            builder: (_) {
              return SinglePermissionRequestPage(
                permissionRequest: permissionRequestArguments.pm,
              );
            },
          );
        } */
      default:
        throw FormatException('Route not found');
    }
  }
}

home_screen.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../bloc/authentication/authentication_bloc.dart';

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final authBloc = BlocProvider.of<AuthenticationBloc>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
        actions: [
          IconButton(
            icon: Icon(Icons.logout),
            onPressed: () {
              authBloc.add(UserLoggedOut());
            },
          )
        ],
      ),
      body: Center(
        child: Text('Home'),
      ),
    );
  }
}

登录.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import '../../bloc/authentication/authentication_bloc.dart';
import '../../bloc/login/login_bloc.dart';
import '../../repositories/interfaces/authentication.dart';
import 'components/loading_login.dart';
import 'components/form_login.dart';

class LoginScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login'),
      ),
      body: SafeArea(
        minimum: const EdgeInsets.all(16),
        child: _AuthForm(),
      ),
    );
  }
}

class _AuthForm extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final AuthenticationRepository authService =
        context.read<AuthenticationRepository>();
    final AuthenticationBloc authBloc = context.read<AuthenticationBloc>();

    return SingleChildScrollView(
      child: BlocProvider<LoginBloc>(
        create: (context) => LoginBloc(authBloc, authService),
        child: SignInForm(),
      ),
    );
  }
}

登录表单

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'loading_login.dart';
import '../../../bloc/login/login_bloc.dart';
import '../../../validation.dart';
import '../../../routes.dart';

class SignInForm extends StatefulWidget {
  @override
  _SignInFormState createState() => _SignInFormState();
}

class _SignInFormState extends State<SignInForm> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final _passwordController = TextEditingController();
  final _emailController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return BlocListener<LoginBloc, LoginState>(
      listener: (context, state) {
        if (state is LoginFailure) {
          _showError(state.error);
        }
      },
      child: BlocBuilder<LoginBloc, LoginState>(
        builder: (context, state) {
          if (state is LoginLoading) {
            return LoadingLogin();
          }
          return Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              Container(
                child: Form(
                  key: _formKey,
                  autovalidateMode: AutovalidateMode.always,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: <Widget>[
                      TextFormField(
                        controller: _emailController,
                        keyboardType: TextInputType.emailAddress,
                        autocorrect: false,
                        validator: (value) => validateEmailAddress(value),
                        decoration: InputDecoration(
                          labelText: 'Indirizzo email',
                          suffixIcon: IconButton(
                            icon: Icon(Icons.close),
                            onPressed: () {
                              _emailController.clear();
                            },
                          ),
                        ),
                      ),
                      SizedBox(
                        height: 12,
                      ),
                      TextFormField(
                        obscureText: true,
                        controller: _passwordController,
                        validator: (value) => validatePassword(value),
                        decoration: InputDecoration(
                          labelText: 'Password',
                          suffixIcon: IconButton(
                            icon: Icon(Icons.close),
                            onPressed: () {
                              _passwordController.clear();
                            },
                          ),
                        ),
                      ),
                      SizedBox(
                        height: 20.0,
                      ),
                      RaisedButton(
                        padding: const EdgeInsets.all(16),
                        child: Text('LOG IN'),
                        onPressed: () => _formKey.currentState.validate()
                            ? onLoginButtonPressed(context)
                            : null,
                      ),
                      SizedBox(
                        height: 10.0,
                      ),
                      FlatButton(
                        child: Text('Registrati'),
                        onPressed: () => Navigator.pushReplacementNamed(
                          context,
                          RouteGenerator.registerScreen,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  void onLoginButtonPressed(BuildContext context) {
    context.read<LoginBloc>().add(
          LoginInWithEmailButtonPressed(
            email: _emailController.text,
            password: _passwordController.text,
          ),
        );
  }

  void _showError(String error) {
    Scaffold.of(context).showSnackBar(
      SnackBar(
        content: Text(error),
        backgroundColor: Theme.of(context).errorColor,
      ),
    );
  }
}

register_screen.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import '../../bloc/authentication/authentication_bloc.dart';
import '../../bloc/registration/registration_bloc.dart';
import '../../repositories/interfaces/authentication.dart';
import '../../screens/home/home_screen.dart';
import '../../screens/register/components/loading_registration.dart';
import 'components/form_registration.dart';

class RegisterScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Registrati'),
      ),
      body: SafeArea(
        minimum: const EdgeInsets.all(16),
        child: _FormRegistration(),
      ),
    );
  }
}

class _FormRegistration extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final AuthenticationRepository authService =
        context.read<AuthenticationRepository>();
    final AuthenticationBloc authBloc = context.read<AuthenticationBloc>();

    return SingleChildScrollView(
      child: BlocProvider<RegistrationBloc>(
        create: (context) => RegistrationBloc(authBloc, authService),
        child: FormRegistration(),
      ),
    );
  }
}

表格注册

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:login/bloc/authentication/authentication_bloc.dart';

import '../../../routes.dart';
import 'loading_registration.dart';
import '../../../models/user.dart';
import '../../../screens/home/home_screen.dart';
import '../../../validation.dart';
import '../../../bloc/registration/registration_bloc.dart';

class FormRegistration extends StatefulWidget {
  @override
  _FormRegistrationState createState() => _FormRegistrationState();
}

class _FormRegistrationState extends State<FormRegistration> {
  final GlobalKey<FormState> _registrationFormKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _firstNameController = TextEditingController();
  final _lastNameController = TextEditingController();
  final _passwordController = TextEditingController();
  final _confirmPasswordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return BlocListener<RegistrationBloc, RegistrationState>(
      listener: (context, state) {
        if (state is RegistrationFailure) {
          _showError(state.error);
        }

        if (state is RegistrationSuccess) {
          context.read<AuthenticationBloc>().add(
                UserLoggedIn(
                  user: User(
                    email: '',
                    firstName: '',
                    lastName: '',
                  ),
                ),
              );
        }
      },
      child: BlocBuilder<RegistrationBloc, RegistrationState>(
        builder: (context, state) {
          if (state is RegistrationLoading) {
            return LoadingRegistration();
          }

          return Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              SizedBox(
                height: 5,
              ),
              Container(
                child: Form(
                  key: _registrationFormKey,
                  autovalidateMode: AutovalidateMode.always,
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: <Widget>[
                      TextFormField(
                        controller: _firstNameController,
                        keyboardType: TextInputType.emailAddress,
                        autocorrect: false,
                        validator: (value) => validateFirstName(value),
                        decoration: InputDecoration(
                          labelText: 'Nome',
                          suffixIcon: IconButton(
                            icon: Icon(Icons.close),
                            onPressed: () {
                              _firstNameController.clear();
                            },
                          ),
                        ),
                      ),
                      TextFormField(
                        controller: _lastNameController,
                        keyboardType: TextInputType.emailAddress,
                        autocorrect: false,
                        validator: (value) => validateLastName(value),
                        decoration: InputDecoration(
                          labelText: 'Cognome',
                          suffixIcon: IconButton(
                            icon: Icon(Icons.close),
                            onPressed: () {
                              _lastNameController.clear();
                            },
                          ),
                        ),
                      ),
                      TextFormField(
                        controller: _emailController,
                        keyboardType: TextInputType.emailAddress,
                        autocorrect: false,
                        validator: (value) => validateEmailAddress(value),
                        decoration: InputDecoration(
                          labelText: 'Indirizzo email',
                          suffixIcon: IconButton(
                            icon: Icon(Icons.close),
                            onPressed: () {
                              _emailController.clear();
                            },
                          ),
                        ),
                      ),
                      TextFormField(
                        obscureText: true,
                        controller: _passwordController,
                        validator: (value) => validatePassword(value),
                        decoration: InputDecoration(
                          labelText: 'Password',
                          suffixIcon: IconButton(
                            icon: Icon(Icons.close),
                            onPressed: () {
                              _passwordController.clear();
                            },
                          ),
                        ),
                      ),
                      TextFormField(
                        obscureText: true,
                        controller: _confirmPasswordController,
                        validator: (value) => validateConfirmPassword(
                          value,
                          _passwordController.text,
                        ),
                        decoration: InputDecoration(
                          labelText: 'Conferma Password',
                          suffixIcon: IconButton(
                            icon: Icon(Icons.close),
                            onPressed: () {
                              _confirmPasswordController.clear();
                            },
                          ),
                        ),
                      ),
                      SizedBox(
                        height: 20.0,
                      ),
                      RaisedButton(
                        padding: const EdgeInsets.all(16),
                        child: Text('Registrati'),
                        onPressed: () =>
                            _registrationFormKey.currentState.validate()
                                ? onRegisterButtonPressed(context)
                                : null,
                      ),
                      FlatButton(
                        padding: const EdgeInsets.all(16),
                        child: Text('Torna al login'),
                        onPressed: () => Navigator.pushNamed(
                          context,
                          RouteGenerator.loginScreen,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  void onRegisterButtonPressed(BuildContext context) {
    final User user = new User(
      firstName: _firstNameController.text,
      lastName: _lastNameController.text,
      email: _emailController.text,
      password: _passwordController.text,
    );
    context.read<RegistrationBloc>().add(
          RegisterButtonPressed(
            user: user,
          ),
        );
  }

  void _showError(String error) {
    Scaffold.of(context).showSnackBar(
      SnackBar(
        content: Text(error),
        backgroundColor: Theme.of(context).errorColor,
      ),
    );
  }
}

登录区块

import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
import 'package:equatable/equatable.dart';

import '../authentication/authentication_bloc.dart';
import '../../models/user.dart';
import '../../exceptions/authentication_exception.dart';
import '../../repositories/interfaces/authentication.dart';

part 'login_event.dart';
part 'login_state.dart';

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  final AuthenticationBloc _authenticationBloc;
  final AuthenticationRepository _authenticationRepository;

  LoginBloc(
    AuthenticationBloc authenticationBloc,
    AuthenticationRepository authenticationRepository,
  )   : assert(authenticationBloc != null),
        assert(authenticationRepository != null),
        _authenticationBloc = authenticationBloc,
        _authenticationRepository = authenticationRepository,
        super(null);

  @override
  LoginState get initialState => LoginInitial();

  @override
  Stream<LoginState> mapEventToState(LoginEvent event) async* {
    if (event is LoginInWithEmailButtonPressed) {
      yield* _mapLoginWithEmailToState(event);
    }
  }

  Stream<LoginState> _mapLoginWithEmailToState(
    LoginInWithEmailButtonPressed event,
  ) async* {
    yield LoginLoading();

    try {
      final User user =
          await _authenticationRepository.signInWithEmailAndPassword(
        event.email,
        event.password,
      );

      if (user is User) {
        // push new authentication event
        _authenticationBloc.add(
          UserLoggedIn(
            user: user,
          ),
        );
        yield LoginSuccess();
        yield LoginInitial();
      } else {
        yield LoginFailure(
          error: 'Something very weird just happened',
        );
      }
    } on AuthenticationException catch (e) {
      yield LoginFailure(
        error: 'I dati di login non sono corretti.',
      );
    } catch (e) {
      yield LoginFailure(
        error: 'Si è verificato un errore sconosciuto, riprova più tardi.',
      );
    }
  }
}

注册区块

import 'dart:async';
import 'package:login/exceptions/registration_exception.dart';
import 'package:meta/meta.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

import '../../repositories/interfaces/authentication.dart';
import '../../models/user.dart';
import '../../bloc/authentication/authentication_bloc.dart';

part 'registration_event.dart';
part 'registration_state.dart';

class RegistrationBloc extends Bloc<RegistrationEvent, RegistrationState> {
  final AuthenticationBloc _authenticationBloc;
  final AuthenticationRepository _authenticationRepository;

  RegistrationBloc(
    AuthenticationBloc authenticationBloc,
    AuthenticationRepository authenticationRepository,
  )   : assert(authenticationBloc != null),
        assert(authenticationRepository != null),
        _authenticationBloc = authenticationBloc,
        _authenticationRepository = authenticationRepository,
        super(null);

  @override
  RegistrationState get initialState => RegistrationInitial();

  @override
  Stream<RegistrationState> mapEventToState(
    RegistrationEvent event,
  ) async* {
    if (event is RegisterButtonPressed) {
      yield RegistrationLoading();

      try {
        final bool registered =
            await _authenticationRepository.registerUser(event.user);

        if (registered) {             

          yield RegistrationSuccess();
          yield RegistrationInitial();
        } else {
          yield RegistrationFailure(
            error: 'Non è stato possibile registrarti.',
          );
        }
      } on RegistrationException catch (e) {
        yield RegistrationFailure(
          error: 'Errore nella registrazione',
        );
      } catch (e) {
        yield RegistrationFailure(
          error: 'Si è verificato un errore sconosciuto.',
        );
      }
    }
  }
}

身份验证块

import 'package:meta/meta.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

import '../../repositories/interfaces/authentication.dart';
import '../../models/user.dart';

part 'authentication_event.dart';
part 'authentication_state.dart';

class AuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationState> {
  final AuthenticationRepository _authenticationService;

  AuthenticationBloc(AuthenticationRepository authenticationService)
      : assert(authenticationService != null),
        _authenticationService = authenticationService,
        super(null);

  @override
  AuthenticationState get initialState => AuthenticationInitial();

  @override
  Stream<AuthenticationState> mapEventToState(
      AuthenticationEvent event) async* {
    if (event is AppLoaded) {
      yield* _mapAppLoadedToState(event);
    }

    if (event is UserLoggedIn) {
      yield* _mapUserLoggedInToState(event);
    }

    if (event is UserLoggedOut) {
      yield* _mapUserLoggedOutToState(event);
    }
  }

  Stream<AuthenticationState> _mapAppLoadedToState(AppLoaded event) async* {
    yield AuthenticationLoading(); // Display splash screen
    try {
      final _currentUser = await _authenticationService.getCurrentUser();

      if (_currentUser != null) {
        yield AuthenticationAuthenticated(
          user: _currentUser,
        );
      } else {
        yield AuthenticationNotAuthenticated(); // Show login form
      }
    } catch (e) {
      yield AuthenticationFailure(message: e.message ?? "An error occured");
    }
  }

  Stream<AuthenticationState> _mapUserLoggedInToState(
    UserLoggedIn event,
  ) async* {
    yield AuthenticationAuthenticated(
      user: event.user,
    );
  }

  Stream<AuthenticationState> _mapUserLoggedOutToState(
    UserLoggedOut event,
  ) async* {
    await _authenticationService.signOut();
    yield AuthenticationNotAuthenticated();
  }
}

如上所述,登录就像一个魅力,注册屏幕只是不要在家里重定向我。
我曾尝试使用调试器,似乎在我将事件添加到 AuthBloc 后,它会重新评估注册构建器并重新构建表单,而不是返回主文件并评估 authBloc。

enter image description here

0 个答案:

没有答案