Changelog¶
5.11.0¶
- Added
MutableStateFlow<T>.collectAsMutableState()
to create a two-way binding. - Added
MutableState.beforeUpdate
,MutableState.afterUpdate
andMutableState.withSetter
setter interceptors (similar to the existingMutableStateFlow
based API). - Added
State.toMutable
which can turn aState
into aMutableState
with a custom setter (similar to the existingStateFlow
based API).
5.10.0¶
- Improved experimental Jetpack Compose APIs (
ReactiveViewModel
,by reactiveViewModel
). - Support for Compose APIs on iOS and JS targets.
5.9.0¶
- Added
JvmSerializable
. DeprecatedSerializable
which is now an alias forJvmSerializable
. - Added
RawSerializer
interface which can serialize an object to/fromByteArray
. - Added
JvmSerializerReplacement
which can be used withwriteReplace()
.
5.8.1¶
- Build reactivestate-compose for all targets.
- Added WASM target.
5.8.0¶
- Upgraded to Kotlin 2.0.0.
5.7.0¶
- Upgraded to Kotlin 1.9.22.
- Switched
derived
andAutoRunner
default dispatcher todispatcher.main
, to prevent threading errors on iOS by default. - Added
MutableStateFlow<T>.onStateSubscription {}
andStateFlow<T>.onStateSubscription {}
which behave likeonSubscription
but return aMutableStateFlow
/StateFlow
.
5.6.0¶
- Upgraded to kotlinx.coroutines 1.7.3.
- Added
MutableStateFlow<Int>.incrementFrom(MutableStateFlow<Boolean>)
.
5.5.7¶
- Fixed rare multi-threading race condition during initialization of (Co)AutoRunner where the worker coroutine would trigger the listener before the constructor has finished executing.
5.5.6¶
- Fixed error propagation for
CoroutineLauncher.derived
.
5.5.5¶
- Made
stateOnDemand
emit current value directly on start by default, so the flow doesn’t have to do it. PassemitValueOnStart = false
as an optimization in case you emit the first value yourself.
5.5.4¶
- Made
.value
access onderived
andstateOnDemand
synchronously return/recompute an up-to-date value. This prevents race conditions when mutating MutableStateFlows and directly reading derived values.
5.5.3¶
- Fixed race condition where suspend-based
derived
would do the first evaluation outside of the flow coroutine, thus preventing cancellation on value change when usingtransformLatest
or other...Latest
based workers.
5.5.2¶
- Downgraded to Gradle 7 since some libraries aren’t ready yet for JDK 17
5.5.1¶
- Simplified
derived
implementation
5.5.0¶
derived
withoutCoroutineScope
now computes on demand only
5.4.2¶
- Downgraded to coroutines 1.6.4 to prevent build failures with Ktor.
5.4.1¶
- Fixed
LifecycleStateFlow
and indirectlyautoRun
andderived
- Added
runWithResolver
/coRunWithResolver
helpers for evaluating anAutoRunner
observer block without subscribing.
5.4.0¶
- Upgraded to Kotlin 1.8.21 which fixes the compilation speed regression.
- Added
Flow<T>.stateOnDemand { ...getter... }
which creates aStateFlow
without requiring aCoroutineScope
(unlikestateIn
). - Added
Flow<T>.shareOnDemand()
andsharedFlow {} which creates a
SharedFlowwithout requiring a
CoroutineScope(unlike
shareIn`). - Added
LifecycleStateFlow
for observing the lifecycle state as aStateFlow
. - Added
LifecycleOwner.launchOnceStateAtLeast
which can be used in place of Android’s deprecatedlaunchWhenStarted
etc. - Added
LifecycleOwner.onceStateAtLeast
which can be used in place of Android’s deprecatedwhenStarted
etc. and which can run asuspend fun
unlike Android’swithStateAtLeast
. - Re-added Jetpack Compose helpers. Currently only available for Android.
- Added
StateFlow.toMutable
which can turn aStateFlow
into aMutableStateFlow
with a custom setter.
5.3.0¶
- Added
T.runCatchingNonFatal
. Contributed by @brudaswen. Thank you!
5.2.1¶
- Made
Wrapped
aSerializable
on JVM. - Added
Serializable
interface that maps to the JVMSerializable
and is usable fromcommonMain
.
5.2.0¶
- Extracted non-Android code into reactivestate-core(-test) modules, so you can use ReactiveState with minimal dependencies.
- Added
MutableStateFlow.afterUpdate
to complete the API introduced in version 5.1.0.
5.1.3¶
- Upgraded to Kotlin 1.7.21.
5.1.2¶
- Downgraded to Kotlin 1.7.20 because of huge compilation speed degradation on iOS targets and incompatibility with Compose.
5.1.1¶
- Improved Swift compatibility of
eventNotifier
by making the lambdas non-suspend
.
5.1.0¶
- Added
MutableStateFlow.beforeUpdate
andMutableStateFlow.withSetter
setter interceptors. - Upgraded to Kotlin 1.8.0.
- Due to the deprecation of the old JS compiler in Kotlin 1.8.0 the code has switched to the IR compiler.
5.0.2¶
- Upgraded to Kotlin 1.7.20, kotlinx.coroutines 1.6.4, androidx.activity 1.6.0, androidx.fragment 1.5.3.
- Upgraded to Android SDK 33.
- The experimental reactivestate-compose module is not published in this release due to a Kotlin/Compose compiler bug.
5.0.1¶
- Adjusted
EventNotifierTest
/ReactiveStateTest
to be consistent with the coroutines test lib behavior. You have to callrunCurrent()
to execute any coroutines launched from the ViewModel’sinit
block.
5.0.0¶
- Upgraded to kotlinx.coroutines 1.6.1. You might need to adjust your unit tests to take behavioral differences into account.
- Upgraded to Jetpack Compose 1.1.1.
- Upgraded to Kotlin 1.6.20.
CoroutineTest.runBlockingTest
was deprecated and you should now useCoroutineTest.runTest
. Similarly,testCoroutineScope
=>testScope
andtestCoroutineDispatcher
=>testDispatcher
.- Use
CoroutineTest.testScope
only for coroutines that will terminate. ForReactiveStateTest
you should useCoroutineTest.mainScope
which gets canceled at the end of each test run. - Native targets are compiled using the experimental memory manager.
- The reactivestate-test module can now be used with all targets instead of just JVM.
- Added a few more targets like macosArm64 and iosSimulatorArm64.
- Moved
get(LiveData)
to thecom.ensody.reactivestate
package, so you don’t need to think twice about where you want to import from.
4.7.0¶
- Added
Throwable.throwIfFatal()
,Throwable.isFatal()
andrunCatchingNonFatal
to deal with fatal errors likeCancellationException
in a simpler and platform-specific way.
4.6.2¶
- Fixed
derived
not replaying the current value.
4.6.1¶
- Fixed
derived
andderivedWhileSubscribed
bug when used with multiple collectors. - Fixed
derived
withWhileSubscribed
subscribe/unsubscribe/re-subscribe bug.
4.6.0¶
- Added
derived
andderivedWhileSubscribed
variants which don’t need aCoroutineScope
, so you don’t need to infect your business logic with scopes.
4.5.0¶
- Upgraded to Kotlin 1.6.10 and Jetpack Compose 1.1.0-rc01.
- Internal improvements.
4.4.0¶
- Added experimental Jetpack Compose support (currently Android-only). By adding
com.ensody.reactivestate:reactivestate-compose
to your dependencies and you can use theviewModel { MyViewModel() }
andreactiveState { ... }
Composable
s.
4.3.2¶
- Fixed race condition with
autoRun
’s observables being changed during run.
4.3.1¶
- Fixed race condition with
derived
where the observedStateFlow
gets changed during first run.
4.3.0¶
- Added
@DependencyAccessor
annotation to ensure the DI pattern is respected instead of the service locator pattern.
4.2.1¶
- Fixed recursively changing the value of a
MutableValueFlow
from within thecollect
block (change->emit->change). Previously this could lead to a deadlock because the first change is still locking theMutableValueFLow
.
4.2.0¶
- Added
OnReactiveStateAttached
interface to allow customizingby reactiveState
behavior.
4.1.0¶
- Added
MutableValueFlow<Int>.incrementFrom(flow: StateFlow<Int>)
extension function to e.g. sum multiple loading states into oneMutableValueFlow<Int>
.
4.0.0¶
This release adds support for Kotlin Multiplatform and introduces a multiplatform ReactiveState
ViewModel.
Breaking changes:
- The modules have been restructured and renamed:
reactivestate-bom
(previously dependency-versions-bom)reactivestate
(previously core and reactivestate)reactivestate-test
(previously core-test)CoroutineTestRule
is now a simple class that you can either derive from or add as an attribute.CoroutineTest
has become independent of JUnit and inherits fromCoroutineTestRule
. ThecoroutineTestRule
attribute has been replaced with directtestCoroutineScope
andtestCoroutineDispatcher
attributes inherited from the newCoroutineTestRule
.- The
withLoading
concept inautoRun
,CoroutineLauncher
etc. has become more flexible to allow tracking separate loading states. - Removed
ReducingStateFlow
as part of the simplified loading state concept.
Non-breaking changes:
- Added a multiplatform ViewModel
ReactiveState
(interface),BaseReactiveState
(base class). This is actually a broader concept that can be used for any living object that can launch coroutines, automatically handles errors, triggers events, and tracks loading states. - Added a multiplatform
buildViewModel
extension function for creating such aViewModel
on an Activity and Fragment. - Improved automatic error catching for
autoRun
andderived
. - Fixes for lifecycle observers:
onCreate
,onCreateView
,onCreateViewOnce
,onDestroyView
,onDestroyViewOnce
. MutableValueFlow.replaceLocked
returns the previous value now.
Known limitations which will be solved with later releases:
- On non-JVM platforms,
dispatchers.io
currently equalsDispatchers.Default
. - This primarily affects
MutableValueFlow
: Internally, all uses of the JVM-onlysynchronized
have been replaced with a spinlockMutex
since they were only utilized for very tiny blocks of code which normally don’t even have any parallel access. Be careful about doing too large computations in combination with highly concurrent updates viareplaceLocked
, though.
Changelog of preview releases:
- 4.0.0-dev.4:
- Fixed build failures due to Jacoco integration.
- 4.0.0-dev.3:
- Removed
ReducingStateFlow
. - Publish iOS/macOS builds.
- 4.0.0-dev.2:
- Improved automatic error catching for
autoRun
andderived
. - Fixes for lifecycle observers
- Removed
LoadingStateTracker
. - Replaced
CoroutineLauncher.isAnyLoading
andgeneralLoading
with a simpleloading: MutableValueFlow<Int>
. MutableValueFlow.replaceLocked
returns the previous value now.MutableValueFlow.increment
/decrement
now have an optionalamount
argument to increment by more than 1. Also, they return the previous value.- 4.0.0-dev.1: This preview release comes without macOS/iOS builds. A port of the CI pipeline is in progress.
3.9.0¶
- Added
@ExperimentalReactiveStateApi
annotation to mark experimental APIs. - Explicitly marked
SuspendMutableValueFlow
as experimental and changed its constructor to take the default value instead of a delegatingMutableValueFlow
. - Turned
SuspendMutableValueFlow
into an interface and constructor/factory function.
3.8.3¶
- Fixed argument inconsistency in
SuspendMutableValueFlow.replace
.
3.8.2¶
- Fixed state restoration with
SavedStateHandleStore
.
3.8.1¶
- Fixed support for nullable values in
SavedStateHandleStore
.
3.8.0¶
- Added
by propertyName
andby lazyProperty
helpers simplifyingReadOnlyProperty
.
3.7.0¶
MutableValueFlow
’s constructor now optionally takes asetter
lambda function which is executed before emitting a new value. This allows observing / reacting to changes without needing aCoroutineScope
.- Added
val Fragment/Activity.savedInstanceState
helper which gives you access to aStateFlowStore
where you can put saved instance state. - Added
by stateFlowViewModel
helpers which work likeby stateViewModel
but use aStateFlowStore
. - Added
by Fragment/Activity.savedInstanceState(default)
andby StateFlowStore.getData(default)
and extension function which automatically uses a key based on the property name. SavedStateHandleStore
now provides an alternative constructor with doesn’t require aCoroutineScope
and only has one-wayMutableValueFlow -> LiveData
sync (which covers the 99% use-case).
3.6.0¶
- Added
SuspendMutableValueFlow
for values that must be mutated via a suspend fun.
3.5.0¶
- The lambda function for
WhileUsed
now receives aWhileUsedReferenceToken
which has a lazyscope
attribute in case you need aCoroutineScope
with the same lifetime as yourWhileUsed
value. - Fixed
withLoading
behavior of firstderived
calculation.
3.4.0¶
- Added
buildOnViewModel
which allows creating arbitrary objects living on an internally-created wrapper ViewModel. - Added
MutableStateFlow.replace
andMutableValueFlow.replaceLocked
helper functions for simplifying e.g. data classcopy()
based mutation.
3.3.0¶
- Added
NamespacedStateFlowStore
. - Added
ReducingStateFlow
.
3.2.1¶
- Moved from JCenter to Maven Central (JCenter is shutting down). Make sure your
repositories
block looks like this:
repositories {
google()
mavenCentral()
// ...
}
3.2.0¶
CoroutineTest
now implementsAttachedDisposables
and disposes at the end ofrunBlockingTest
.CoroutineTest
providescollectFlow
to easily collect aderived
withWhileSubscribed()
in background.
3.1.1¶
- Fixed
withErrorReporting
to really accept a suspension function.
3.1.0¶
- Added
withErrorReporting
to handle suspension functions and optionalonError
. - Added
EventNotifier.handleEvents
helpers for Kotlin and Android. The Android version takes aLifecycleOwner
. - Added
EventNotifierTest
.
3.0.0¶
Breaking changes:
- IMPORTANT: In order to overcome a limitation, the
flowTransformer
argument ofderived
/coAutoRun
/CoAutoRunner
must now map over lambda functions and execute them. E.g.:mapLatest { it() }
. Without theit()
no value will ever be recomputed! - The default
flowTransformer
has changed from{ mapLatest { } }
to{ conflatedWorker() }
. There is alsolatestWorker
if you want the old behavior. - The possible arguments to
derived
were changed a little bit in order to improve compatibility withWhileUsed
. Either you must remove thestarted: SharingStarted
argument or additionally pass aninitial
value. - If you leave out the
started
argumentderived
behaves like before when passingEagerly
: the value is computed immediately and synchronously and you can’t callsuspend
functions within the observer. - Otherwise, you have to pass an
initial
value. In this case,derived
is asynchronous and you can callsuspend
functions within the observer. - The default value for
started
is nowEagerly
because that has better safety guarantees. So, in most usages the whole argument can now be removed (except where you really needWhileSubscribed()
, for example). - Removed bindings because they turned out to not be useful enough.
Resolver.track()
now returns theAutoRunnerObservable
instead of theunderlyingObservable
.
Non-breaking changes:
- Added
WhileUsed
for reference-counted singletons that get garbage-collected when all consumers’CoroutineScope
s end. - Added
conflatedWorker
,latestWorker
anddebouncedWorker
as simpleflowTransformer
s for the suspend-basedderived
/coAutoRun
. - Added
conflatedMap
helper for mapping first and last elements and - whenever possible - intermediate elements. - Added simple
ErrorEvents
interface andwithErrorReporting(eventNotifier) { ... }
for easy error handling. MutableFlow.tryEmit
now returns aBoolean
.
Legal change:
- Switched license to Apache 2.0.
2.0.4¶
- Upgraded dependencies (coroutines 1.4.3, androidx.lifecycle 2.3.0, fragment-ktx 1.3.1)
2.0.2¶
- Fixed BOM (reactivestate was missing).
2.0.0¶
Breaking changes:
- Moved all Android-related code to the
com.ensody.reactivestate.android
package to avoid method resolution ambiguity. - Removed
CoroutineScopeOwner
(replaced byCoroutineLauncher
).
Non-breaking changes:
- Added
CoroutineLauncher
interface to allow overriding howautoRun
/derived
launch their coroutines (e.g. to include custom error handling or a loading state). - Added
coAutoRun
andCoAutoRunner
andderived
variants which take suspension functions and usemapLatest
.
1.1.0¶
StateFlowStore.getData()
now returns aMutableValueFlow
1.0.0¶
derived
now takes a mandatorystarted: SharingStarted
argument - similar tostateIn
/shareIn
(WhileSubscribed()
,Lazily
,Eagerly
, etc.)
0.15.4¶
- Fixed
CoroutineTest
.
0.15.3¶
- Added support for using
CoroutineTest
by delegation (preventing multiple inheritance situations).
0.15.2¶
- Added
buildViewModel
andstateViewModel
extension functions forActivity
.
0.15.0¶
derived
supports an optionallazy = true
argument to observe lazily.- Added a global
dispatchers
API for replacingDispatchers
(Main
,IO
, etc.) in a way that allows switching toTestCoroutineDispatcher
in unit tests. - Added coroutine unit test helpers in the
com.ensody.reactivestate:core-test
module: CoroutineTest
base class for tests that use coroutines. This sets upMainScope
,dispatchers.io
, etc. to useTestCoroutineDispatcher
.CoroutineTestRule
a test rule for setting up coroutines.CoroutineTestRuleOwner
a helper interface in case you can’t useCoroutineTest
, but still want minimal boilerplate.- Removed
launchWhileStarted
andlaunchWhileResumed
. - Added
dependency-versions-bom
platform project. You can now include the versions of all modules like this:
dependencies {
// Add the BOM using the desired ReactiveState version
api platform("com.ensody.reactivestate:dependency-versions-bom:VERSION")
// Now you can leave out the version number from all other ReactiveState modules:
implementation "com.ensody.reactivestate:core" // For Kotlin-only projects
implementation "com.ensody.reactivestate:reactivestate" // For Android projects
implementation "com.ensody.reactivestate:core-test" // Utils for unit tests that want to use coroutines
}
0.14.0¶
- Fixed
MutableValueFlow.value
assignment to havedistinctUntilChanged
behavior. This should provide the best of both worlds: emit
/tryEmit
/update
always emit.value
behaves exactly like withMutableStateFlow
0.13.0¶
After a long period of tuning the API and use at several companies this release introduces the hopefully last set of major breaking changes.
This is the final migration to Flow
-based APIs like StateFlow
/SharedFlow
/ValueFlow
and removal of obsolete APIs.
autoRun
now auto-disposes inActivity.onDestroy
/Fragment.onDestroyView
, so usually it should be launched inActivity.onCreate()
/Fragment.onCreateView()
(previouslyonStart()
). It still automatically observes only betweenonStart()
/onStop()
.- Removed
MutableLiveDataNonNull
and other non-null LiveData helpers. UseMutableStateFlow
andMutableValueFlow
instead. - Added
MutableValueFlow
which implementsMutableStateFlow
, but doesn’t havedistinctUntilChanged
behavior and offers an in-placeupdate { it.attr = ... }
method. This makes it safer and easier to use with mutable values. - Removed
DerivedLiveData
. UseDerivedStateFlow
/derived
instead. - Replaced
workQueue
with the much simplerEventNotifier
which allows sending one-time events to the UI. - Replaced
Scoped
with a simpleCoroutineScopeOwner
interface. - Upgraded to Kotlin 1.4.10.
0.12.0¶
Breaking changes (migration to StateFlow
):
derived
now returns aStateFlow
instead of aLiveData
, so you can usederived
in multiplatform code.LiveDataStore
has been replaced withStateFlowStore
, so you can write multiplatform code.InMemoryStore
has been replaced withInMemoryStateFlowStore
.SavedStateHandleStore
now implementsStateFlowStore
and requires aCoroutineScope
in addition toSavedStateHandle
.State
has been renamed toScoped
(more descriptive).
Other changes:
- Added
StateFlow
-based API for bindings. TheLiveData
-based API is still available.
0.11.4¶
- Switched to
api
instead ofimplementation
for most dependencies.
0.11.3¶
- Fixed edge case with
autoRun
onLiveData
incorrectly ignoring the first notification.
0.11.2¶
- Fixed release packaging of Android reactivestate package.
0.11¶
ATTENTION: There’s a breaking change to support StateFlow
.
- Added experimental
StateFlow
support toautoRun
(StateFlow
was added inkotlinx-coroutines-core
1.3.6). - Breaking change: Removed
CoroutineContext.autoRun
andsuspend fun autoRun
because properStateFlow
support requires access to aCoroutineScope
.
0.10¶
- Added
thisWorkQueue
helper for passing an arg viathis
. argWorkQueue
now supports suspension functions.- Added
AttachedDisposables
interface for objects that can clean up other disposables. AutoRunner
now implementsAttachedDisposables
.- Added
OnDispose { ... }
class for triggering a function when itsdispose()
method is called. - Added
onDestroyView { ... }
,onDestroy
,onCreate
,onCreateView
and their...Once
variants. - Added
validUntil
for properties that are only valid during a lifecycle subset. - Further documentation improvements.
0.9.1¶
This release introduces no code changes.
- Fixed release publication on jcenter.
- Minor documentation improvements.
0.9¶
ATTENTION: Due to the core & reactivestate module split you have to also add the core module to your dependencies as described in the installation instructions.
- This release splits the
reactivestate
module into a Kotlin module (core
) and an Android module (reactivestate
). The change is backwards-compatible unless you’ve accessedBaseAutoRunner
(very unlikely). - Added
State
base class for separating business logic fromViewModel
, making it easier to use in normal unit tests. - Added
argWorkQueue
, arg-basedconsume
andconsumeConflated
helpers for ViewModel -> UI event/notification use-case. - Fixed one-level recursion when observing
LiveData
. - Documentation improvements.
0.8¶
ATTENTION: This release comes with a few breaking changes.
- Bindings don’t have value converters, anymore. Usually you need to store the raw field value and a separate conversion (if possible without errors), anyway. Use
autoRun
orderived
to convert values. - Added bindings for
CompoundButton
(replacingCheckBox
bindings). AutoRunner
’s andautoRun
’sobserver
callback now receives theResolver
viathis
instead of as an argument (more consistent and compact code). You can writeget(livedata)
to retrieve aLiveData
value.AutoRunner
’s andautoRun
’sonChange
callback now receives theAutoRunner
as its first argument.- Improved
AutoRunner
’s null handling ofLiveData
. - Added
onResume
,onResumeOnce
,onPause
,onPauseOnce
,launchWhileResumed
lifecycle observers. - Added
Disposable.disposeOnCompletionOf(coroutineContext)
extension methods. - Added
WorkQueue
and helpers likeconflatedWorkQueue
for simpler communication between UI and ViewModel. - Added unit tests.
- Added simple documentation with API reference.
0.5¶
Initial release.