Kotlin-Bloc

website·Indexed 30 days ago

https://1gravity.github.io/Kotlin-Bloc/

A BLoC (Business Logic Component) implementation for Kotlin, featuring core components such as BlocStateBase, ComponentLazy, and support for thunks, reducers, and side effects.

Tokens
39K
Snippets
293
Records
347
Agent score
74%

What's inside Kotlin-Bloc

  1. Understand the Redux and Reselect libraries used by Kotlin-Bloc

    The bloc-redux extension is built upon two libraries:

    1. Redux Kotlin: A port of JS Redux serving as the state container. Due to maintenance issues with the original library, Kotlin-Bloc uses a fork maintained by 1gravity, published on Maven Central.
    2. Reselect: A Kotlin implementation of Redux Reselect used to create memoized selector functions. These functions select and subscribe to specific sub-states of the Redux state tree, informing callers of changes while ignoring unrelated state updates and caching results transparently. The Reselect library is bundled directly within the Redux extension module.
  2. Integrate Redux store as BlocState using ReduxBlocState

    The ReduxBlocState allows a Redux store to function as a BlocState. It enables the following behavior:

    • Proposals as Actions: Proposals dispatched to the Bloc are sent to the Redux store without modification, acting as Redux actions.
    • State Selection: A selector function extracts a specific sub-state (ReduxModel) from the global Redux state tree.
    • State Mapping: A mapper function converts that ReduxModel into the specific State type required by the Bloc.

    This integration allows the use of Redux middleware (e.g., thunk-middleware) and independent Redux reducers while maintaining the Bloc architecture.

  3. Understand the Kotlin Bloc architecture

    Kotlin Bloc is a Multiplatform UI framework that combines MVI, MVVM, and SAM patterns. It separates business logic from state management to ensure predictability and testability.

    Key architectural components include:

    • Bloc (Business Logic Component): Encapsulates business logic. It receives Action(s) from the view, processes them, and outputs Proposals and optional SideEffect(s).
    • BlocState: A separate entity that holds the component's State. This separation allows for sharing state between components, persisting state to databases or networks, or integrating with global state containers like Redux.
  4. Understand Kotlin-Bloc Architecture

    A Bloc implements business logic by processing event data (Actions) from the UI. It performs two primary roles: updating the State based on business rules for the UI to consume, and optionally creating SideEffects for the UI (e.g., navigation) or other consumers (e.g., analytics, logging).
  5. Observe state and side effects using BlocObservable

    The BlocObservable abstract class allows a Bloc to be observed by subscribing to its state and side effect updates. Subscriptions are tied to the provided Lifecycle object; the specific lifecycle transitions that trigger subscription/unsubscription (such as onStart() and onStop()) are determined by the concrete implementation of the BlocObservable.
  6. Use MutableStateStream to manage state and input

    MutableStateStream is a utility class that implements both StateStream and Sink. It acts as a wrapper around MutableSharedFlow, allowing a developer to both emit new values (via the Sink interface) and collect the current state (via the StateStream interface).
    // Initialize with a starting value
    val stateStream = MutableStateStream(initialValue = "Initial State")
  7. Implement BlocObservableOwner to expose Bloc state and side effects

    The BlocObservableOwner interface is used by classes (such as ViewModels, Fragments, or Activities) that hold and expose a BlocObservable. Implementing this interface allows other components to subscribe to the bloc's state and side effect updates using a simplified one-liner syntax. Note that if a component is already a BlocOwner, it does not need to implement BlocObservableOwner because BlocOwner is already observable and supports the same extension functions.
    interface BlocObservableOwner<out State : Any, out SideEffect : Any> {
        override val observable: BlocObservable<State, SideEffect>
    }
  8. Kotlin Bloc Data Flow Concepts: Sinks and Streams

    The architecture utilizes specific nomenclature for data movement:

    • Sink: A destination for arbitrary data used to pass information to the next component. Processing can be synchronous or asynchronous depending on the receiver.
    • Stream: A source of asynchronous "hot" data, meaning data is emitted regardless of whether a component is currently subscribed or collecting.
  9. Understand the Kotlin Bloc Reducer definition

    In Kotlin Bloc, a reducer is a function that receives the current state and an action, and returns a Proposal (rather than the state directly). Reducers are executed within a ReducerContext, which provides access to the current state and the action that triggered the execution.
    public data class ReducerContext<State, Action>(
        val state: State,
        val action: Action
    )
  10. Implement business logic using the Bloc class

    The Bloc abstract class is the core of the framework. It implements business logic by processing Action data from the UI and performing two primary tasks:

    1. Updating the State according to business rules and emitting it to the UI.
    2. Optionally creating SideEffects for the UI (e.g., navigation) or other consumers (e.g., analytics, logging).

    Because Bloc extends BlocState, it provides a StateStream for emitting state and a Sink for accepting actions. It also includes a SideEffectStream for emitting side effects.

    abstract class Bloc<out State : Any, in Action : Any, SideEffect : Any> : BlocState<State, Action>
  11. Use StateStream for asynchronous state data

    The StateStream<out Value : Any> interface represents a hot stream of asynchronous state data. It is functionally similar to kotlinx.coroutines.flow.StateFlow but does not expose the replayCache.

    Key characteristics of a StateStream include:

    • No duplicate values: It only emits when the state actually changes.
    • Initial value: It emits the current state immediately upon subscription (similar to a BehaviorSubject).

    This is distinct from a SideEffectStream, which emits all values (including duplicates) and provides no initial value upon subscription (similar to a PublishSubject).