Abstraction experiment. Kotlin library to create a communication network between different business logic blocks for your Android Projects.
Business logic can accumulate for complex screens in Android quite quickly.
Business logic is abstracted to some controller class, UseCase, or something similar to control and maintain the complexity.
However, the reactive nature of the data we present on the screen often prevents us from genuinely decoupling this logic. For example, in scenarios where one part of the screen controls another, they must be updated together.
This library brings an additional layer to this complexity, intending to decouple the business logic blocks from each other.
You can read more about motivation and how the library works here.
The library is distributed through Jitpack.
Add the repository to the root build.gradle
repositories {
maven { url("https://jitpack.io") }
}
Add the library to the dependencies block of your app's module build.gradle (And any module you need to use)
implementation("com.github.Trendyol:transmission:<latest_version>")
The library consists of the following building blocks:
- Transmission: Unit of information being transferred. Three subtypes are: signal, effect, and data.
- Transformer: Processes transmission. Might receive signal or effect and might produce either an effect or data.
- TransmissionRouter: Processes incoming signals and effects and passes along the produced data. Responsible for distributing the signals and effects between Transformers.
Transmission
interactions are depicted below:
graph TD;
Signal --> Effect
Signal --> Data
Effect --> Data
Effect --> Effect
Transformers are responsible for handling signal
s and effect
s. They have an inner class called TransmissionHataHolder
which can hold any Data type that is extended from Transmission.Data
. Any update to the dataHolder automatically publishes the latest version to Data Channel.
class InputTransformer @Inject constructor() : DefaultTransformer() {
private val holder = buildDataHolder(InputUiState())
init {
registerComputation<WrittenInput> {
delay(1.seconds)
WrittenInput(holder.value.writtenText)
}
}
override val signalHandler = buildTypedSignalHandler<InputSignal> { signal ->
when (signal) {
is InputSignal.InputUpdate -> {
holder.update { it.copy(writtenText = signal.value) }
publish(effect = InputEffect.InputUpdate(signal.value))
}
}
}
override val effectHandler = buildGenericEffectHandler { effect ->
when (effect) {
is ColorPickerEffect.BackgroundColorUpdate -> {
holder.update { it.copy(backgroundColor = effect.color) }
}
}
}
}
Possibly in your ViewModel:
init {
transmissionRouter.initialize(onData = {}, onEffect = {})
}
The TransmissionRouter takes a set of Transformer
s as a parameter. Building the Router heavily depends on your app's architecture and dependency injection choices. Here is an approach from the sample app using Hilt:
@InstallIn(ViewModelComponent::class)
@Module
interface FeaturesModule {
@Multibinds
fun bindTransformerSet(): Set<DefaultTransformer>
@Binds
@IntoSet
fun bindInputTransformer(impl: InputTransformer): DefaultTransformer
@Binds
@IntoSet
fun bindOutputTransformer(impl: OutputTransformer): DefaultTransformer
@Binds
@IntoSet
fun bindColorPickerTransformer(impl: ColorPickerTransformer): DefaultTransformer
@Binds
@IntoSet
fun bindMultiOutputTransformer(impl: MultiOutputTransformer): DefaultTransformer
companion object {
@Provides
fun provideRouter(
transformerSet: @JvmSuppressWildcards Set<DefaultTransformer>
): DefaultTransmissionRouter {
return TransmissionRouter(transformerSet)
}
}
}
This library is released under the MIT license. See LICENSE for details.