BLoC (Business Logic Component) — állapotkezelési minta Flutterhez, amelyet a Google 2018-ban mutatott be a DartConf-on. A BLoC elválasztja az üzleti logikát a felhasználói felülettől reaktív adatfolyamok (Stream) segítségével: az UI elküld egy Event-et, a BLoC feldolgozza és új State-et ad vissza a Stream-en keresztül. A pub.dev adatai szerint a flutter_bloc csomag több mint 11 ezer like-ot gyűjtött és több ezer Flutter alkalmazásban használják.
Főbb pontok
BLoC (Business Logic Component) — architekturális minta Flutterhez, amelyben az üzleti logika egy külön osztályba van kiszervezve, elkülönítve az UI-tól. A BLoC bemeneti adatokat fogad az események adatfolyamán (Event) keresztül, és kimeneti adatokat állít elő az állapotok adatfolyamán (State) keresztül. A prezentációs réteg (Widget) csak feliratkozik a State adatfolyamra és megjeleníti az UI-t, soha nem hajt végre közvetlenül üzleti logikát.
A BLoC koncepció a reaktív programozáson és az Observer mintán alapul. Minden BLoC komponens egy külön modul, egyértelmű szerződéssel: ismert az Event halmaz (mi történhet) és a State halmaz (mi jeleníthető meg). A fejlesztő nem tud "véletlenül" állapotot változtatni az UI-ból — csak egy konkrét Event-en keresztül. Ez kiszámíthatóvá és tesztelhetővé teszi a kódot.
A Flutter Community 2025 felmérése szerint a BLoC a második helyen áll a népszerűségben a Flutter állapotkezelési megoldásai között a Provider után. Fő előnyök: szigorú típusosság, logika elkülönítése, beépített Stream támogatás, gazdag segédprogram ökoszisztéma (BlocProvider, BlocListener, BlocSelector).
BLoC architektúra három entitás köré épül: Event (bemenet), Bloc (feldolgozó) és State (kimenet). A Widget az add() metóduson keresztül küldi el az Event-et. A Bloc az Event-et a mapEventToState vagy on<Event> metódusban fogadja, végrehajtja az üzleti logikát és új State-et állít elő a yield segítségével. A Widget a State-et a Stream-en keresztül kapja és újrarajzolódik.
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0);
@override
Stream<int> mapEventToState(CounterEvent event) async* {
if (event is Increment) {
yield state + 1;
} else if (event is Decrement) {
yield state - 1;
}
}
}Típusbiztonság: A Bloc két típussal van paraméterezve — Event és State. A Dart fordító ellenőrzi, hogy a Widget csak deklarált Event-eket hívjon, és a Bloc csak deklarált State-eket adjon vissza. Az "Ismeretlen Művelet" típusú futásidejű hibák ki vannak zárva.
Close és Dispose: A Bloc implementálja a Closeable interfészt. A widget megsemmisítésekor a Bloc automatikusan bezárja a Stream-et a close() metóduson keresztül. Reaktív feliratkozások szivárgása lehetetlen — a BlocProvider kezeli a Bloc életciklusát, egy útvonalhoz vagy oldalhoz kötve azt.
Cubit — a Bloc egyszerűsített implementációja Event nélkül, a flutter_bloc 6.0 csomagban bevezetve. A Cubit közvetlenül metódusokat deklarál az Event osztályok helyett: increment(), fetchData(). Belsőleg a Cubit ugyanazt a Stream-alapú mechanizmust használja, de elrejti az Event réteget. Ez 40-50%-kal csökkenti a boilerplate-ot egyszerű forgatókönyvek esetén.
| Jellemző | Bloc | Cubit |
|---|---|---|
| Event osztályok | Kötelezőek | Nem szükségesek |
| Boilerplate | Magas | Alacsony |
| Műveletek követése | Event típuson keresztül | Csak metódusnév |
| Alkalmas | Összetett forgatókönyvek | Egyszerű állapotok |
| Analitika | Automatikus Event-en keresztül | Kézi |
Mikor válasszuk a Cubit-ot: állapot 2-3 változattal (loading, loaded, error), egyszerű űrlapok, számlálók, UI állapotok (nyitva/zárva). Mikor Bloc: összetett üzleti logika sok művelettel: rendelés leadása, hitelesítés, adatszinkronizáció. A Bloc részletes nyomonkövetést biztosít minden műveletről Event-en keresztül — minden hívás naplózásra kerül a BlocObserver-ben.
BlocObserver — globális megfigyelő, amely az összes Bloc-ot és Cubit-ot követi az alkalmazásban. Lehetővé teszi az Event, State, hibák és átmenetek naplózását. Elég egy példányt csatlakoztatni: Bloc.observer = AppBlocObserver(), és az alkalmazás állapotának teljes nyomonkövetése központilag elérhető.
BlocProvider — InheritedWidget a flutter_bloc-ból, amely a Bloc-ot elérhetővé teszi a gyermek widgetek számára. A widget inicializálásakor a BlocProvider létrehoz egy Bloc-ot, és megsemmisítéskor automatikusan bezárja a close() segítségével. A BlocProvider elhelyezhető MaterialApp szinten (globális Bloc) vagy egy adott útvonal szintjén (lokális Bloc).
BlocProvider(
create: (context) => CounterBloc(),
child: Column(
children: [
BlocBuilder<CounterBloc, int>(
builder: (context, state) => Text('$state'),
),
ElevatedButton(
onPressed: () => context.read<CounterBloc>().add(Increment()),
child: Text('+'),
),
],
),
)BlocBuilder — widget, amely minden új State-nél újraépíti az UI-t. BlocListener — mellékhatásokhoz (egyszeri State feldolgozás UI újraépítés nélkül): SnackBar megjelenítése, navigáció másik képernyőre. BlocConsumer — a Builder és Listener kombinációja olyan esetekre, amikor mind újraépítés, mind mellékhatás szükséges. BlocSelector — szelektív újraépítéshez csak a State egy adott mezőjének változásakor.
MultiBlocProvider — widget egymásba ágyazott BlocProvider-ekhez a beágyazási szint növelése nélkül. A 10-15 Bloc-ot használó Flutter alkalmazás a gyökér szinten használ MultiBlocProvider-et az összes, a teljes alkalmazás számára elérhető Bloc regisztrálásához: AuthenticationBloc, CartBloc, SettingsBloc.
A BLoC tesztelése elkülönítve történik, Flutter widgetek nélkül. Elég importálni a Dart flutter_test csomagot és a bloc_test csomagot. Teszt forgatókönyv: Bloc létrehozása, Event hozzáadása, State ellenőrzése. blocTest — segédprogram, amely automatizálja a build → act → expect sorozatot.
blocTest<CounterBloc, int>(
'emits [1] when Increment is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Increment()),
expect: () => [1],
)Mocking: A repository-tól vagy API-tól függő BLoC mock-okkal tesztelhető a mocktail segítségével. A repository absztrakciós szinten van mock-olva, a Bloc a mock-olt függőségeket a konstruktoron keresztül kapja. Hydrated Bloc — kiterjesztés az állapot automatikus mentéséhez/visszaállításához helyi tárolóban. HydratedBlocStorage-al és ideiglenes fájltárolóval tesztelhető.
Mappák és fájlok: egy BLoC-os Flutter projekt tipikus struktúrája: bloc/counter_bloc.dart, bloc/counter_event.dart, bloc/counter_state.dart. 30+ képernyő esetén funkcionalitás szerinti csoportosítás ajánlott: features/auth/bloc/, features/cart/bloc/. Minden Bloc külön fájl, minden Event és State — vagy külön fájlokban, vagy egy fájlban a Bloc-kal.
Teljesítmény: A BLoC nem hoz létre többletterhelést üres Stream-eken. A BlocBuilder a buildWhen segítségével szűri az újraépítéseket — a widget csak egy adott feltétel változásakor frissül. A Close garantálja, hogy az inaktív Bloc-ok nem fogyasztanak memóriát. A Flutter DevTools szerint a BLoC kevesebb mint 1%-ot ad hozzá a bundle méretéhez.
Migráció Provider-ről: A BLoC könnyen együtt él a Provider-rel ugyanabban a projektben. Fokozatos migráció: először a legösszetettebb Provider-ek kerülnek Bloc-ra cserélésre, majd a többiek. A BlocProvider kompatibilis a Provider fával: a régi widgetek használhatják a Provider-t, az újak — a BlocProvider-t, ugyanabban az alkalmazásban.
Gyakran Ismételt Kérdések
BLoC Event + Stream-et használ az üzleti logika elkülönítésére és szigorú típusosságra. Provider — burkoló az InheritedWidget körül egyszerű függőséginjektáláshoz és ChangeNotifier-hez. A BLoC jobban megfelel összetett, több állapotú forgatókönyvekhez, a Provider — lokális UI állapothoz. A BLoC több boilerplate-et igényel, de teljes nyomonkövethetőséget biztosít az Event-en keresztül.
Hydrated Bloc — kiterjesztés a hydrated_bloc csomagból, amely automatikusan elmenti az utolsó State-et a helyi tárolóba (alapértelmezetten Hive). Az alkalmazás újraindításakor a Bloc a mentett állapotot állítja vissza a kezdeti helyett. Ez megoldja a perzisztencia problémáját kézi mentési hívás nélkül: bejelentkezés, kosár, beállítások automatikusan mentésre kerülnek a munkamenetek között.
A BLoC-ban a hibát try-catch segítségével kezeljük a mapEventToState vagy on<Event> belsejében. Hiba esetén a Bloc egy hiba State-et ad vissza: yield LoadError(error.message). Az UI-n a BlocListener vagy BlocConsumer ellenőrzi a State-et a hiba típusára, és megjelenít egy SnackBar-t vagy dialógust. A BlocObserver globálisan naplóz minden kezeletlen kivételt.
A BLoC — Flutter-specifikus minta, mivel Dart Stream-et és Flutter widgeteket használ. Az Event → Bloc → State koncepció adaptálható AngularDart és Server-side Dart számára, de a fő ökoszisztéma (BlocProvider, BlocBuilder, BlocObserver) a Flutter-hez kötődik. React Native-hez használjon Redux-ot vagy MobX-et, SwiftUI-hez — Combine + MVVM-et.
Cubit — egyszerű állapotokhoz (számláló, toggle, 2-3 mezős űrlap). Bloc — összetett logikához (hírfolyam, rendelés leadása, hitelesítés). Fő szabály: ha minden művelet (Event) nyomonkövetése szükséges analitikához vagy hibakereséshez — Bloc. Ha az állapotot módosító metódusok elegendőek — Cubit. Mindkét minta együtt élhet ugyanabban a projektben.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is