Giter Site home page Giter Site logo

flutter-blocarchitecture's Introduction

Flutter Bloc Architecture

flutter_bloc pub package

Flutter Widgets that make it easy to implement the BLoC (Business Logic Component) design pattern. Built to be used with the bloc state management package.

Why Bloc?

Bloc makes it easy to separate presentation from business logic, making your code fast, easy to test, and reusable.

When building production quality applications, managing state becomes critical.

As developers we want to:

  • know what state our application is in at any point in time.
  • easily test every case to make sure our app is responding appropriately.
  • record every single user interaction in our application so that we can make data-driven decisions.
  • work as efficiently as possible and reuse components both within our application and across other applications.
  • have many developers seamlessly working within a single code base following the same patterns and conventions.
  • develop fast and reactive apps.

There are many state management solutions and deciding which one to use can be a daunting task.

Bloc was designed with three core values in mind:

  • Simple

    • Easy to understand & can be used by developers with varying skill levels.
  • Powerful

    • Help make amazing, complex applications by composing them of smaller components.
  • Testable

    • Easily test every aspect of an application so that we can iterate with confidence.

Bloc attempts to make state changes predictable by regulating when a state change can occur and enforcing a single way to change state throughout an entire application.

Architecture

Bloc Architecture

Using Bloc allows us to separate our application into three layers:

  • Data

    • Data Provider

    • Repository

  • Business Logic

  • Presentation

We're going to start at the lowest level layer (farthest from the user interface) and work our way up to the presentation layer.

Data Layer

The data layer's responsibility is to retrieve/manipulate data from one or more sources.

The data layer can be split into two parts:

  • Repository
  • Data Provide

This layer is the lowest level of the application and interacts with databases, network requests, and other asynchronous data sources.

Data Provider

The data provider's responsibility is to provide raw data. The data provider should be generic and versatile.

The data provider will usually expose simple APIs to perform CRUD operations. We might have a createData, readData, updateData, and deleteData method as part of our data layer.

#Login Request

@JsonSerializable()
class LoginRequest {
  String email;
  String password;

  LoginRequest({
    this.email,
    this.password,
  });

  factory LoginRequest.fromJson(Map<String, dynamic> json) =>
      _$LoginRequestFromJson(json);

  Map<String, dynamic> toJson() => _$LoginRequestToJson(this);
}

#Login Response

@JsonSerializable()
class LoginResponse {
  String status;
  int code;
  String message;
  Result result;

  LoginResponse({
    this.status,
    this.code,
    this.message,
    this.result,
  });

  factory LoginResponse.fromJson(Map<String, dynamic> json) =>
      _$LoginResponseFromJson(json);

  Map<String, dynamic> toJson() => _$LoginResponseToJson(this);
}

Repository

The repository layer is a wrapper around one or more data providers with which the Bloc Layer communicates.

class ApiRepository {
  ApiRestClient apiRestClient;

  ApiRepository() {
    Dio _dio = Dio();
    _dio.options.headers["Content-Type"] = "application/json";
    apiRestClient = ApiRestClient(_dio);
  }

  Future<LoginResponse> login({
    @required String email,
    @required String password,
  }) async {
    LoginRequest loginRequest = LoginRequest(
      email: email,
      password: password,
    );
    return await ApiRestClient(Dio()).login(loginRequest);
  }
}

As you can see, our repository layer can interact with multiple data providers and perform transformations on the data before handing the result to the business logic Layer.

Bloc (Business Logic) Layer

The bloc layer's responsibility is to respond to events from the presentation layer with new states. The bloc layer can depend on one or more repositories to retrieve data needed to build up the application state.

Think of the bloc layer as the bridge between the user interface (presentation layer) and the data layer. The bloc layer takes events generated by user input and then communicates with repository in order to build a new state for the presentation layer to consume.

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  final ApiRepository apiRepository;
  final Validator validator = Validator();

  LoginBloc({@required this.apiRepository});

  @override
  LoginState get initialState => UserUnavailable();

  @override
  Stream<LoginState> mapEventToState(LoginEvent event) async* {
    if (event is SignInUser) {
      yield LoginLoading();
      try {
        LoginResponse loginResponse = await apiRepository.login(
          email: event.email,
          password: event.password,
        );
        if (loginResponse != null) {
          Helper.printLogValue("UserLoggedIn");
          yield UserLoggedIn();
        } else {
          Helper.printLogValue("UserLoggedOut");
          yield UserLoggedOut();
        }
      } catch (error) {
        Helper.printLogValue("LoginFailure");
        yield LoginFailure(error: error.toString());
      }
    }
    if (event is PasswordChanged) {
      yield state.copyWith(
        isPasswordValid: _isPasswordValid(event.password),
      );
    }

    if (event is EmailChanged) {
      yield state.copyWith(
        isEmailValid: _isEmailValid(event.email),
      );
    }
  }

  bool _isEmailValid(String email) {
    return validator.validateEmail(email);
  }

  bool _isPasswordValid(String password) {
    return validator.validatePassword(password);
  }
}

Presentation Layer

The presentation layer's responsibility is to figure out how to render itself based on one or more bloc states. In addition, it should handle user input and application lifecycle events.

     Container(
      width: size.width,
      height: kBottomNavigationBarHeight,
      child: BlocListener<LoginBloc, LoginState>(
        listener: (context, state) {
          if (state is UserLoggedIn) {
            Navigator.of(context).pushNamedAndRemoveUntil(
                PageRouteConstants.home_screen,
                (Route<dynamic> route) => false);
          } else if (state is LoginFailure) {
            Helper.showAlert(context, StringConstant.error_message,
                StringConstant.invalid_user_credentials);
          }
        },
        child: BlocBuilder<LoginBloc, LoginState>(
          builder: (context, state) {
            if (state is LoginLoading) {
              return Helper.progressWidget(progressKey);
            } else {
              return RaisedButton(
                child: Text(
                  StringConstant.sign_in,
                  style: AppTextStyles.getMediumText(
                      size.width, AppColors.white, FontConstant.kSemiBold),
                ),
                onPressed: () {
                  if (!(_emailController.text.length > 0) ||
                      !state.isEmailValid) {
                    showInSnackBar(StringConstant.invalid_email);
                  } else if (!(_passwordController.text.length > 0) ||
                      !state.isPasswordValid) {
                    showInSnackBar(StringConstant.invalid_password);
                  } else {
                    Helper.checkConnectivity().then((internetStatus) {
                      if (internetStatus) {
                        if (progressKey.currentWidget == null) {
                          BlocProvider.of<LoginBloc>(context).add(
                            SignInUser(
                              email: _emailController.text,
                              password: _passwordController.text,
                            ),
                          );
                        }
                      } else {
                        Helper.showAlert(context, StringConstant.internet_alert,
                            StringConstant.please_check_internet_connectivity);
                      }
                    });
                  }
                },
                color: Theme.of(context).primaryColor,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(Dimens.px28),
                ),
              );
            }
          },
        ),
      ),
    );

Pros of BLoC

  • Easy to separate UI from logic
  • Easy to test code
  • Easy to reuse code
  • Good performance

Cons of BLoC

  • Technically, you need to use streams in both directions, creating a lot of boilerplate. However, many people cheat this by using streams only from the backend to the UI, but when events occur they’re simply calling functions directly instead of feeding those events into a sink.

  • More boilerplate for small app, but it can be worth it for anything larger than a small app.

Refrences

  1. https://bloclibrary.dev
  2. https://pub.dev/packages/bloc
  3. https://flutter.dev/
  4. https://blog.codemagic.io/flutter-tutorial-pros-and-cons-of-state-management-approaches/

flutter-blocarchitecture's People

Contributors

ashishrawat2911 avatar manojaeologic avatar viranderaeologic avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.