El patró Bloc (Business Logic Component) és una de les arquitectures més populars per a la gestió de l'estat en aplicacions Flutter. Aquest patró separa la lògica de negoci de la interfície d'usuari, facilitant la mantenibilitat i la testabilitat del codi.

Objectius del Patró Bloc

  • Separació de la lògica de negoci i la interfície d'usuari: Permet que la lògica de negoci es mantingui independent de la interfície d'usuari.
  • Reutilització de codi: Facilita la reutilització de la lògica de negoci en diferents parts de l'aplicació.
  • Testabilitat: Millora la capacitat de testejar la lògica de negoci de manera aïllada.

Components del Patró Bloc

  1. Bloc: Conté la lògica de negoci i gestiona els esdeveniments i els estats.
  2. Esdeveniments: Representen les accions que poden ocórrer en l'aplicació (per exemple, un usuari fa clic en un botó).
  3. Estats: Representen els diferents estats possibles de la interfície d'usuari.

Implementació del Patró Bloc

  1. Instal·lació del Paquet flutter_bloc

Per començar a utilitzar el patró Bloc, primer hem d'instal·lar el paquet flutter_bloc. Afegeix la següent línia al fitxer pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^8.0.0

Després, executa flutter pub get per instal·lar el paquet.

  1. Creació dels Esdeveniments

Els esdeveniments són accions que poden ocórrer en l'aplicació. Creem una classe abstracta per als esdeveniments i les seves subclasses concretes.

import 'package:equatable/equatable.dart';

abstract class CounterEvent extends Equatable {
  const CounterEvent();

  @override
  List<Object> get props => [];
}

class Increment extends CounterEvent {}

class Decrement extends CounterEvent {}

  1. Creació dels Estats

Els estats representen els diferents estats possibles de la interfície d'usuari. Creem una classe abstracta per als estats i les seves subclasses concretes.

import 'package:equatable/equatable.dart';

abstract class CounterState extends Equatable {
  const CounterState();

  @override
  List<Object> get props => [];
}

class CounterInitial extends CounterState {
  final int count;

  const CounterInitial(this.count);

  @override
  List<Object> get props => [count];
}

  1. Creació del Bloc

El Bloc conté la lògica de negoci i gestiona els esdeveniments i els estats.

import 'package:bloc/bloc.dart';

class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(const CounterInitial(0)) {
    on<Increment>((event, emit) {
      final currentState = state;
      if (currentState is CounterInitial) {
        emit(CounterInitial(currentState.count + 1));
      }
    });

    on<Decrement>((event, emit) {
      final currentState = state;
      if (currentState is CounterInitial) {
        emit(CounterInitial(currentState.count - 1));
      }
    });
  }
}

  1. Integració del Bloc amb la Interfície d'Usuari

Finalment, integrem el Bloc amb la interfície d'usuari utilitzant els widgets BlocProvider i BlocBuilder.

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (context) => CounterBloc(),
        child: CounterPage(),
      ),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(
        child: BlocBuilder<CounterBloc, CounterState>(
          builder: (context, state) {
            if (state is CounterInitial) {
              return Text('Count: ${state.count}');
            }
            return CircularProgressIndicator();
          },
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(Increment()),
            child: Icon(Icons.add),
          ),
          SizedBox(height: 8),
          FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(Decrement()),
            child: Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

Exercici Pràctic

Objectiu

Crear una aplicació Flutter que utilitzi el patró Bloc per gestionar un comptador que es pot incrementar i decrementar.

Passos

  1. Instal·la el paquet flutter_bloc.
  2. Defineix els esdeveniments Increment i Decrement.
  3. Defineix l'estat CounterInitial.
  4. Implementa el Bloc CounterBloc.
  5. Integra el Bloc amb la interfície d'usuari.

Solució

// pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^8.0.0

// counter_event.dart
import 'package:equatable/equatable.dart';

abstract class CounterEvent extends Equatable {
  const CounterEvent();

  @override
  List<Object> get props => [];
}

class Increment extends CounterEvent {}

class Decrement extends CounterEvent {}

// counter_state.dart
import 'package:equatable/equatable.dart';

abstract class CounterState extends Equatable {
  const CounterState();

  @override
  List<Object> get props => [];
}

class CounterInitial extends CounterState {
  final int count;

  const CounterInitial(this.count);

  @override
  List<Object> get props => [count];
}

// counter_bloc.dart
import 'package:bloc/bloc.dart';

class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(const CounterInitial(0)) {
    on<Increment>((event, emit) {
      final currentState = state;
      if (currentState is CounterInitial) {
        emit(CounterInitial(currentState.count + 1));
      }
    });

    on<Decrement>((event, emit) {
      final currentState = state;
      if (currentState is CounterInitial) {
        emit(CounterInitial(currentState.count - 1));
      }
    });
  }
}

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (context) => CounterBloc(),
        child: CounterPage(),
      ),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: Center(
        child: BlocBuilder<CounterBloc, CounterState>(
          builder: (context, state) {
            if (state is CounterInitial) {
              return Text('Count: ${state.count}');
            }
            return CircularProgressIndicator();
          },
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(Increment()),
            child: Icon(Icons.add),
          ),
          SizedBox(height: 8),
          FloatingActionButton(
            onPressed: () => context.read<CounterBloc>().add(Decrement()),
            child: Icon(Icons.remove),
          ),
        ],
      ),
    );
  }
}

Conclusió

El patró Bloc és una eina poderosa per gestionar l'estat en aplicacions Flutter, proporcionant una clara separació entre la lògica de negoci i la interfície d'usuari. Amb aquest patró, podem crear aplicacions més mantenibles, testables i escalables.

Curs de Desenvolupament Flutter

Mòdul 1: Introducció a Flutter

Mòdul 2: Conceptes Bàsics de Programació en Dart

Mòdul 3: Widgets de Flutter

Mòdul 4: Gestió de l'Estat

Mòdul 5: Navegació i Enrutament

Mòdul 6: Xarxes i APIs

Mòdul 7: Persistència i Emmagatzematge

Mòdul 8: Conceptes Avançats de Flutter

Mòdul 9: Proves i Depuració

Mòdul 10: Desplegament i Manteniment

Mòdul 11: Flutter per a Web i Escriptori

© Copyright 2024. Tots els drets reservats