ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

Sealed State Machine: Network Request Lifecycle

Kotlin

Goal -- WPM

Ready
Exercise Algorithm Area
1import kotlinx.coroutines.delay
2import kotlin.random.Random
3
4// Define the sealed states for the network request lifecycle
5sealed interface NetworkState {
6object Idle : NetworkState
7object Loading : NetworkState
8data class Success(val data: String) : NetworkState
9data class Error(val message: String) : NetworkState
10}
11
12// Define the possible actions that can trigger state transitions
13sealed interface NetworkAction {
14object Fetch : NetworkAction
15data class SuccessResponse(val responseData: String) : NetworkAction
16data class ErrorResponse(val errorMessage: String) : NetworkAction
17}
18
19/**
20* Manages the state transitions for a network request.
21*/
22class NetworkStateMachine {
23private var currentState: NetworkState = NetworkState.Idle
24
25/**
26* Processes an action and transitions the state accordingly.
27* @param action The action to process.
28* @return The new state after processing the action.
29*/
30fun processAction(action: NetworkAction): NetworkState {
31val nextState = when (currentState) {
32is NetworkState.Idle -> {
33when (action) {
34NetworkAction.Fetch -> NetworkState.Loading
35is NetworkAction.SuccessResponse -> NetworkState.Idle // Unexpected success in Idle
36is NetworkAction.ErrorResponse -> NetworkState.Idle // Unexpected error in Idle
37}
38}
39is NetworkState.Loading -> {
40when (action) {
41NetworkAction.Fetch -> NetworkState.Loading // Already loading, ignore or re-fetch logic
42is NetworkAction.SuccessResponse -> NetworkState.Success(action.responseData)
43is NetworkAction.ErrorResponse -> NetworkState.Error(action.errorMessage)
44}
45}
46is NetworkState.Success -> {
47when (action) {
48NetworkAction.Fetch -> NetworkState.Loading // Fetch again after success
49is NetworkAction.SuccessResponse -> currentState // Received success while already in success, ignore
50is NetworkAction.ErrorResponse -> NetworkState.Error(action.errorMessage) // Transition to error from success
51}
52}
53is NetworkState.Error -> {
54when (action) {
55NetworkAction.Fetch -> NetworkState.Loading // Retry after error
56is NetworkAction.SuccessResponse -> NetworkState.Success(action.responseData) // Unexpected success after error
57is NetworkAction.ErrorResponse -> NetworkState.Error(action.errorMessage) // Stay in error state or retry logic
58}
59}
60}
61currentState = nextState
62return currentState
63}
64
65/**
66* Gets the current state of the machine.
67* @return The current NetworkState.
68*/
69fun getCurrentState(): NetworkState {
70return currentState
71}
72}
73
74// --- Example Usage (for demonstration, not part of the core logic) ---
75
76/**
77* Simulates fetching data from a network.
78* Returns a random success or error response.
79*/
80suspend fun simulateNetworkCall(): NetworkAction {
81delay(Random.nextLong(500, 1500))
82return if (Random.nextBoolean()) {
83NetworkAction.SuccessResponse("Data fetched successfully: ${System.currentTimeMillis()}")
84} else {
85NetworkAction.ErrorResponse("Network error: ${Random.nextInt(1000, 9999)}")
86}
87}
88
89/*
90import kotlinx.coroutines.runBlocking
91
92fun main() = runBlocking {
93val stateMachine = NetworkStateMachine()
94
95println("Initial State: ${stateMachine.getCurrentState()}")
96
97// Fetch 1
98var newState = stateMachine.processAction(NetworkAction.Fetch)
99println("After Fetch: $newState")
100
101// Simulate response
102val response1 = simulateNetworkCall()
103newState = stateMachine.processAction(response1)
104println("After Response 1 ($response1): $newState")
105
106// Fetch 2 (e.g., to refresh data)
107newState = stateMachine.processAction(NetworkAction.Fetch)
108println("After Fetch 2: $newState")
109
110// Simulate another response
111val response2 = simulateNetworkCall()
112newState = stateMachine.processAction(response2)
113println("After Response 2 ($response2): $newState")
114
115// Example of an unexpected action
116newState = stateMachine.processAction(NetworkAction.SuccessResponse("Unexpected data"))
117println("After unexpected SuccessResponse: $newState")
118}
119*/
Algorithm description viewbox

Sealed State Machine: Network Request Lifecycle

Algorithm description:

This code defines a sealed state machine for managing the lifecycle of a network request. It uses `sealed interface` to represent distinct states (Idle, Loading, Success, Error) and actions (Fetch, SuccessResponse, ErrorResponse). The `NetworkStateMachine` class holds the current state and a `processAction` method that transitions between states based on the current state and the received action. This pattern ensures type safety and exhaustiveness in handling state changes.

Algorithm explanation:

The `NetworkState` and `NetworkAction` are defined as sealed interfaces, ensuring that all possible states and actions are known at compile time. The `NetworkStateMachine` class maintains the `currentState`. The `processAction` method uses a nested `when` expression to determine the `nextState` based on the `currentState` and the `action`. Transitions like `Idle` to `Loading` on `Fetch`, `Loading` to `Success` on `SuccessResponse`, and `Loading` to `Error` on `ErrorResponse` are explicitly defined. Unexpected transitions (e.g., receiving `SuccessResponse` while in `Idle`) are handled by either staying in the current state or transitioning to a safe default state, preventing invalid state configurations. The time complexity for processing an action is O(1) as it involves simple conditional logic. The space complexity is O(1) as it only stores the current state.

Pseudocode:

DEFINE NetworkState AS SEALED INTERFACE:
  IDLE
  LOADING
  SUCCESS(data)
  ERROR(message)

DEFINE NetworkAction AS SEALED INTERFACE:
  FETCH
  SUCCESS_RESPONSE(responseData)
  ERROR_RESPONSE(errorMessage)

CLASS NetworkStateMachine:
  current_state = IDLE

  FUNCTION processAction(action):
    next_state = CASE current_state:
      WHEN IDLE:
        CASE action:
          WHEN FETCH: RETURN LOADING
          ELSE: RETURN current_state
      WHEN LOADING:
        CASE action:
          WHEN SUCCESS_RESPONSE(data): RETURN SUCCESS(data)
          WHEN ERROR_RESPONSE(message): RETURN ERROR(message)
          ELSE: RETURN current_state
      WHEN SUCCESS(data):
        CASE action:
          WHEN FETCH: RETURN LOADING
          WHEN ERROR_RESPONSE(message): RETURN ERROR(message)
          ELSE: RETURN current_state
      WHEN ERROR(message):
        CASE action:
          WHEN FETCH: RETURN LOADING
          WHEN SUCCESS_RESPONSE(data): RETURN SUCCESS(data)
          ELSE: RETURN current_state

    current_state = next_state
    RETURN current_state

  FUNCTION getCurrentState(): RETURN current_state
END CLASS