EventTransformer və müşahidə (BlocObserver)
Rəsmi sənəd Bloc-un Cubit üzərindəki ikinci üstünlüyünü advanced event transformations adlandırır: buffer, debounce, throttle kimi reaktiv operatorlardan istifadə etmək imkanı.
Mexanizm: on<Event> çağırışına transformer parametri verilir. EventTransformer<T> gələn event axınının bloc tərəfindən necə işlənəcəyini dəyişir.
Hazır transformer-lər package:bloc_concurrency paketindədir:
- `concurrent` — event-ləri paralel işləyir.
- `sequential` — event-ləri bir-bir, ardıcıl işləyir.
- `droppable` — bir event işlənərkən əlavə olunan event-ləri atır.
- `restartable` — yalnız son event-i işləyir, əvvəlkiləri ləğv edir.
| Ssenari | Transformer | Səbəb |
|---|---|---|
| Axtarış sahəsinə yazmaq | `restartable` (+ debounce) | Yalnız son sorğunun nəticəsi lazımdır; köhnə sorğular ləğv olunur |
| "Ödə" düyməsinə iki dəfə basmaq | `droppable` | İkinci sorğu atılır — ikiqat əməliyyatın qarşısı alınır |
| Səhifələmə: "daha çox yüklə" | `droppable` | Scroll zamanı təkrar sorğuların qarşısını alır |
| Analytics event-lərinin göndərilməsi | `sequential` | Ardıcıllıq vacibdir, heç bir event itməməlidir |
| Bir-birindən müstəqil yükləmələr | `concurrent` | Paralel icra ən sürətlidir |
import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:stream_transform/stream_transform.dart';
EventTransformer<E> debounceRestartable<E>(Duration duration) {
return (events, mapper) =>
restartable<E>().call(events.debounce(duration), mapper);
}
class SearchBloc extends Bloc<SearchEvent, SearchState> {
SearchBloc(this._repository) : super(const SearchState()) {
on<SearchQueryChanged>(
_onQueryChanged,
// Sürətli yazılışda yalnız son sorğu işlənir, əvvəlkilər ləğv olunur.
transformer: debounceRestartable(const Duration(milliseconds: 300)),
);
}
final SearchRepository _repository;
Future<void> _onQueryChanged(
SearchQueryChanged event,
Emitter<SearchState> emit,
) async {
if (event.query.isEmpty) {
emit(const SearchState());
return;
}
emit(state.copyWith(status: SearchStatus.loading));
final results = await _repository.search(event.query);
emit(state.copyWith(status: SearchStatus.success, results: results));
}
}Axtarış: debounce + restartable.
Müşahidə: BlocObserver. Bütün bloc və cubit-lərin həyat dövrünü bir yerdən izləmək üçün BlocObserver override olunur:
onCreate— bloc yaradıldıonEvent— bloc-a event əlavə olunduonChange— state dəyişdi (cubit-lərdə də)onTransition— state → event → state keçidi; sənədə görəTransitioncari state, event və növbəti state-dən ibarətdir vəonTransitiononChange-dən əvvəl çağırılıronError— xətaonClose— bloc bağlandı
Qeydiyyat: Bloc.observer = MyObserver(); və ya bir neçəsini birləşdirmək üçün Bloc.observer = MultiBlocObserver(observers: [...]);
Bu, müsahibədə BLoC-un traceability üstünlüyünün konkret sübutudur: log-da hansı event-in hansı state keçidini doğurduğu görünür — Cubit-də event obyekti olmadığı üçün bu məlumat yoxdur.
class AppBlocObserver extends BlocObserver {
const AppBlocObserver();
@override
void onEvent(Bloc bloc, Object? event) {
super.onEvent(bloc, event);
// Audit tələb olunan axınlarda event jurnalı buradan yazılır.
log('${bloc.runtimeType} ← $event');
}
@override
void onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
// Transition: cari state + event + növbəti state.
log('${bloc.runtimeType} ${transition.currentState.runtimeType} '
'--${transition.event.runtimeType}--> ${transition.nextState.runtimeType}');
}
@override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
// Crash reporting servisinə göndərmək üçün mərkəzi nöqtə.
reportError(error, stackTrace, context: bloc.runtimeType.toString());
super.onError(bloc, error, stackTrace);
}
}
void main() {
Bloc.observer = const AppBlocObserver();
runApp(const MyApp());
}Observer: log və crash reporting bir yerdə.
Transformer seçimini təxminə buraxmayın: kritik axınlarda (ödəniş, sifariş yaratma, səhifələmə) transformer parametrini açıq şəkildə yazın və bunu code review checklist-inə salın. "İki dəfə basıldı → iki sifariş" tipli bug-lar məhz sükutla qəbul edilmiş davranışdan doğur.
📚 Mənbələr və sənədlər
- package:bloc_concurrencyrəsmipub.dev
concurrent, sequential, droppable, restartable transformer-lərinin rəsmi təsviri.
- Bloc konseptləri: event transformasiyaları və observerrəsmibloclibrary.dev
EventTransformer, Transition və onTransition/onChange sırası burada izah olunur.
- package:blocrəsmipub.dev
BlocObserver callback-ləri və MultiBlocObserver qeydiyyatı.
- package:hydrated_blocrəsmipub.dev
State-i avtomatik olaraq diskdə saxlayıb bərpa etmək lazım olduqda.