Skip to content

Commit 5821cc3

Browse files
committed
added useSequentialEventProcessing constructor paramter for Bloc constructor
1 parent b5c4ba0 commit 5821cc3

22 files changed

+48
-25
lines changed

kbloc_app/src/main/java/com/beyondeye/kbloc_app/ABCCounterBloc.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class ABCCounterBloc(
1313
Bloc<MultiCounterEvent,
1414
ABCCounterState>(
1515
cscope, ABCCounterState(a= startCounters[0], b=startCounters[1],c=startCounters[2]),
16+
true,
1617
true
1718
) {
1819
init {

kbloc_app/src/main/java/com/beyondeye/kbloc_app/CounterBloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class SubtractionEvent(val value:Int):CounterEvent
1111
data class CounterState(val counter:Int=0)
1212

1313
class CounterBloc(cscope: CoroutineScope, startCounter:Int=0): Bloc<CounterEvent, CounterState>(cscope,
14-
CounterState(startCounter),false
14+
CounterState(startCounter),false,true
1515
) {
1616
init {
1717
on<IncrementEvent> { event, emit ->

kbloc_app/src/main/java/com/beyondeye/kbloc_app/MultiCounterBloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class MultiCounterBloc(
1515
Bloc<MultiCounterEvent,
1616
MultiCounterState>(
1717
cscope, MultiCounterState(counter = startCounters),
18-
true
18+
true,true
1919
) {
2020
init {
2121
on<MultiAddEvent> { event, emit ->

kbloc_core/src/commonMain/kotlin/com/beyondeye/kbloc/core/bloc.kt

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,20 @@ public abstract class Bloc<Event : Any, State : Any>
7272
/**
7373
* in the original dart code this is always false
7474
*/
75-
useReferenceEqualityForStateChanges: Boolean
75+
useReferenceEqualityForStateChanges: Boolean,
76+
/**
77+
* flag that set change parallel/sequential behavior of event processing for a bloc
78+
* in the original flutter_bloc events are processed in parallel by default. This means
79+
* it is possible to have race condition when multiple events are processed in parallel.
80+
* So if multiple event handler will try to update the bloc state in parallel, not necessarily we will
81+
* see the effect of all state changes from all event handler. This very problematic for complex bloc state
82+
* (i.e. bloc state with more than one field that can change independently)
83+
* With bloc with such complex bloc state. you should really use sequential event processing, unless
84+
* you really know what you are doing.
85+
* Note that if [BlocOverrides.current.eventTransformer] is defined that it will take precedence
86+
* on what you specify with the flag [useSequentialEventProcessing]
87+
*/
88+
useSequentialEventProcessing:Boolean,
7689
) : BlocBase<State>(initialState, cscope, useReferenceEqualityForStateChanges), BlocEventSink<Event> {
7790

7891
private var eventFlowJob:Job?=null
@@ -86,7 +99,7 @@ public abstract class Bloc<Event : Any, State : Any>
8699
private val _emitters:MutableList<_Emitter<State>> = mutableListOf()
87100
@PublishedApi
88101
internal val _eventTransformer:EventTransformer<Any> =
89-
BlocOverrides.current?.eventTransformer ?: _defaultEventTransformer
102+
BlocOverrides.current?.eventTransformer ?: if(useSequentialEventProcessing) EventTransformer_sequential() else EventTransformer_concurrent()
90103

91104
init {
92105
_startEventHandlerJob()

kbloc_core/src/commonMain/kotlin/com/beyondeye/kbloc/core/bloc_overrides.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ late final _defaultEventTransformer = (Stream events, EventMapper mapper) {
141141
*
142142
*/
143143
// TODO change the default event transformer to flattenConcat from flattenMerge
144+
// NOTE that this exactly the same as EventTransformer_concurrent
144145
internal val _defaultEventTransformer: EventTransformer<Any> = { events: Flow<Any>, mapper: EventMapper<Any> ->
145146
events
146147
.map(mapper).flattenMerge()

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/async/async_bloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.Flow
88
import kotlinx.coroutines.flow.flatMapConcat
99
import kotlinx.coroutines.flow.flatMapMerge
1010

11-
class AsyncBloc(cscope: CoroutineScope) : Bloc<AsyncEvent,AsyncState>(cscope,AsyncState.initial(),false)
11+
class AsyncBloc(cscope: CoroutineScope) : Bloc<AsyncEvent,AsyncState>(cscope,AsyncState.initial(),false,false)
1212
{
1313
init {
1414
on<AsyncEvent>(transformer = { events,mapper-> events.asyncExpand(mapper) }) { event,emit ->

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/bloc_event_transformer_test.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ suspend fun tick() {
5252
class CounterBloc(
5353
cscope: CoroutineScope,
5454
incrementTransformer: EventTransformer<Increment>?=null
55-
) : Bloc<CounterEvent, Int>(cscope, 0,false) {
55+
) : Bloc<CounterEvent, Int>(cscope, 0,false,false) {
5656
val onCalls= mutableListOf<CounterEvent>()
5757
val onEmitCalls= mutableListOf<CounterEvent>()
5858
init {

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/bloc_on_test.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class TestBloc(cscope:CoroutineScope,
3939
val onTestEventAA :onEvent<TestEventAA,TestState> = { _,_ -> },
4040
val onTestEventBA :onEvent<TestEventBA,TestState> = { _,_ -> },
4141

42-
) : Bloc<TestEvent, TestState>(cscope, TestState(),false)
42+
) : Bloc<TestEvent, TestState>(cscope, TestState(),false,false)
4343
{
4444
init {
4545
on<TestEventA>(handler = onTestEventA)
@@ -49,14 +49,16 @@ class TestBloc(cscope:CoroutineScope,
4949
on<TestEvent>(handler = onTestEvent)
5050
}
5151
}
52-
class DuplicateHandlerBloc(cscope: CoroutineScope) : Bloc<TestEvent,TestState>(cscope, TestState(),false) {
52+
class DuplicateHandlerBloc(cscope: CoroutineScope) : Bloc<TestEvent,TestState>(cscope, TestState(),
53+
false,false) {
5354
init {
5455
on<TestEvent> {_,_-> }
5556
on<TestEvent> {_,_-> }
5657
}
5758
}
5859

59-
class MissingHandlerBloc(cscope: CoroutineScope) : Bloc<TestEvent,TestState>(cscope, TestState(),false) {
60+
class MissingHandlerBloc(cscope: CoroutineScope) : Bloc<TestEvent,TestState>(cscope, TestState(),
61+
false,false) {
6062
init {
6163

6264
}

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/complex/complex_bloc.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import kotlinx.coroutines.CoroutineScope
55
import kotlinx.coroutines.async
66
import kotlinx.coroutines.delay
77
import kotlinx.coroutines.flow.Flow
8+
import kotlinx.coroutines.flow.StateFlow
89
import kotlinx.coroutines.flow.debounce
10+
import kotlinx.coroutines.flow.stateIn
911
import kotlin.time.Duration
1012

1113
const private val _delay_ms:Long =100
1214

13-
class ComplexBloc(cscope:CoroutineScope) : Bloc<ComplexEvent, ComplexState>(cscope,ComplexStateA(),false)
15+
class ComplexBloc(cscope:CoroutineScope) : Bloc<ComplexEvent, ComplexState>(cscope,ComplexStateA(),false,false)
1416
{
1517
init {
1618
on<ComplexEventA> { _,emit ->
@@ -29,6 +31,6 @@ class ComplexBloc(cscope:CoroutineScope) : Bloc<ComplexEvent, ComplexState>(csco
2931
}
3032
}
3133

32-
override val stream: Flow<ComplexState>
33-
get() = super.stream.debounce(50)
34+
override val stream: StateFlow<ComplexState>
35+
get() = super.stream.debounce(50).stateIn(cscope)
3436
}

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/counter/counter_bloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class CounterBloc(cscope:CoroutineScope,
1818
val onEventCallback: OnEventCallback?=null,
1919
val onTransitionCallback: onTransitionCallback?=null,
2020
val onErrorCallback: onErrorCallback?=null
21-
) :Bloc<CounterEvent,Int>(cscope,0,false)
21+
) :Bloc<CounterEvent,Int>(cscope,0,false,false)
2222
{
2323
init {
2424
on<CounterEvent> { event, emit ->

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/counter/counter_error_bloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import kotlinx.coroutines.CoroutineScope
88
* NOTE: in kotlin there is no much difference between Error and Exception like in Dart
99
* so [CounterErrorBloc] and [CounterExceptionBloc] are basically the same thing
1010
*/
11-
class CounterErrorBloc(cscope:CoroutineScope) : Bloc<CounterEvent,Int>(cscope,0,false) {
11+
class CounterErrorBloc(cscope:CoroutineScope) : Bloc<CounterEvent,Int>(cscope,0,false,false) {
1212
init {
1313
on<CounterEvent> { event, emit ->
1414
_onCounterEvent(event,emit)

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/counter/counter_exception_bloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import kotlinx.coroutines.CoroutineScope
88
* NOTE: in kotlin there is no much difference between Error and Exception like in Dart
99
* so [CounterErrorBloc] and [CounterExceptionBloc] are basically the same thing
1010
*/
11-
class CounterExceptionBloc(cscope: CoroutineScope) : Bloc<CounterEvent, Int>(cscope,0,false) {
11+
class CounterExceptionBloc(cscope: CoroutineScope) : Bloc<CounterEvent, Int>(cscope,0,false,false) {
1212
init {
1313
on<CounterEvent> { event, emit ->
1414
_onCounterEvent(event,emit)

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/counter/merge_bloc.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ val customTransformer:EventTransformer<CounterEvent> = { events, mapper ->
1818

1919

2020

21-
class MergeBloc(cscope:CoroutineScope,val onTransitionCallback: onTransitionCallback?=null) : Bloc<CounterEvent, Int>(cscope,0,false) {
21+
class MergeBloc(cscope:CoroutineScope,val onTransitionCallback: onTransitionCallback?=null) : Bloc<CounterEvent, Int>(cscope,0,
22+
false,false) {
2223
init {
2324
on<CounterEvent>(transformer = customTransformer, handler = ::_onCounterEvent)
2425
}

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/counter/on_error_bloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import kotlinx.coroutines.CoroutineScope
1111
class OnErrorBloc(cscope: CoroutineScope,
1212
val error: Throwable,
1313
val onErrorCallback: (Throwable) -> Unit
14-
) : Bloc<CounterEvent, Int>(cscope, 0,false) {
14+
) : Bloc<CounterEvent, Int>(cscope, 0,false,false) {
1515
init {
1616
on<CounterEvent>(handler = ::_onCounterEvent)
1717
}

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/counter/on_event_error_bloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import kotlinx.coroutines.CoroutineScope
66

77
class OnEventErrorBloc(cscope: CoroutineScope,
88
val exception: Exception,
9-
) : Bloc<CounterEvent, Int>(cscope, 0,false) {
9+
) : Bloc<CounterEvent, Int>(cscope, 0,false,false) {
1010
init {
1111
on<CounterEvent> { _,_-> }
1212
}

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/counter/on_exception_bloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import kotlinx.coroutines.CoroutineScope
1111
class OnExceptionBloc(cscope: CoroutineScope,
1212
val exception: Exception,
1313
val onErrorCallback: (Throwable) -> Unit
14-
) : Bloc<CounterEvent, Int>(cscope, 0,false) {
14+
) : Bloc<CounterEvent, Int>(cscope, 0,false,false) {
1515
init {
1616
on<CounterEvent>(handler = ::_onCounterEvent)
1717
}

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/counter/on_transition_error_bloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class OnTransitionErrorBloc(
99
cscope: CoroutineScope,
1010
val error: Throwable,
1111
val onErrorCallback: onErrorCallback
12-
) : Bloc<CounterEvent, Int>(cscope, 0,false) {
12+
) : Bloc<CounterEvent, Int>(cscope, 0,false,false) {
1313
init {
1414
on<CounterEvent>(handler = ::_onCounterEvent)
1515
}

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/seeded/SeededBloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import kotlinx.coroutines.CoroutineScope
66
class SeededBloc (
77
val seed:Int, val states:List<Int>,
88
cscope_stateUpdate: CoroutineScope, useReferenceEqualityForStateChanges: Boolean=false) :
9-
Bloc<String, Int>(cscope_stateUpdate, seed, useReferenceEqualityForStateChanges) {
9+
Bloc<String, Int>(cscope_stateUpdate, seed, useReferenceEqualityForStateChanges,false) {
1010
init {
1111
on<String>{ event, emit ->
1212
for (state in states) {

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/simple/SimpleBloc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.beyondeye.kbloc.core.Bloc
44
import kotlinx.coroutines.CoroutineScope
55

66
class SimpleBloc (cscope_stateUpdate: CoroutineScope, useReferenceEqualityForStateChanges: Boolean=false) :
7-
Bloc<Any, String>(cscope_stateUpdate, "", useReferenceEqualityForStateChanges) {
7+
Bloc<Any, String>(cscope_stateUpdate, "", useReferenceEqualityForStateChanges,false) {
88
init {
99
on<String>{ _, emit ->
1010
emit("data")

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/stream/restartable_stream_bloc.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ public fun Job.catchError(test:((Throwable)->Boolean)?=null,onError:(Throwable)-
9595
return this
9696
}
9797

98-
class RestartableStreamBloc(cscope:CoroutineScope,val inputEventsStream: Flow<Int>) :Bloc<RestartableStreamEvent,Int>(cscope,0,false) {
98+
class RestartableStreamBloc(cscope:CoroutineScope,val inputEventsStream: Flow<Int>) :Bloc<RestartableStreamEvent,Int>(cscope,0,
99+
false,false) {
99100
init {
100101
// message = "Flow analogues of 'switchMap' are 'transformLatest', 'flatMapLatest' and 'mapLatest'",
101102
on<ForEach>(transformer = { events, mapper -> events.flatMapLatest(mapper) })

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/stream/stream_bloc.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class Subscribe : StreamEvent
1313

1414
class OnData(val data:Int) :StreamEvent
1515

16-
class StreamBloc(cscope:CoroutineScope, val inputEventsStream: Flow<Int>) :Bloc<StreamEvent,Int>(cscope,0,false) {
16+
class StreamBloc(cscope:CoroutineScope, val inputEventsStream: Flow<Int>) :Bloc<StreamEvent,Int>(cscope,0,
17+
false,false) {
1718
private var _subscription: Job? = null
1819
init {
1920
//in the original code here there is on<StreamEvent> but it does not work that way, and it actually look like a bug

kbloc_core/src/commonTest/kotlin/com/beyondeye/kbloc/unawaited/unawaited_bloc.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ class UnawaitedEvent
99
class UnawaitedState
1010

1111
class UnawaitedBloc(cscope:CoroutineScope) :
12-
Bloc<UnawaitedEvent,UnawaitedState>(cscope, UnawaitedState(),false) {
12+
Bloc<UnawaitedEvent,UnawaitedState>(cscope, UnawaitedState(),
13+
false,false) {
1314
constructor(cscope: CoroutineScope,future:Deferred<Unit>):this(cscope) {
1415
on<UnawaitedEvent>{ event, emit ->
1516
//TODO the original code is

0 commit comments

Comments
 (0)