Bird
Raised Fist0
Android Kotlinmobile~20 mins

Use cases / Interactors in Android Kotlin - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Simple Use Case Demo
This screen demonstrates how to use a Use Case (Interactor) to fetch and display a greeting message.
Target UI
-------------------------
| Simple Use Case Demo   |
|-----------------------|
|                       |
|  Greeting:            |
|  [__________________] |
|                       |
|  [Fetch Greeting]      |
|                       |
-------------------------
Create a Use Case class that returns a greeting string.
Create a ViewModel that calls the Use Case.
Display the greeting message on the screen.
Add a button labeled 'Fetch Greeting' that triggers the Use Case call.
Show a loading indicator while fetching.
Handle the UI state with LiveData or StateFlow.
Starter Code
Android Kotlin
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: android.os.Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      val viewModel = GreetingViewModel()
      GreetingScreen(viewModel)
    }
  }
}

// TODO: Create UseCase class here

// TODO: Create ViewModel class here

@Composable
fun GreetingScreen(viewModel: GreetingViewModel) {
  // TODO: Implement UI with greeting text, loading indicator, and button
}
Task 1
Task 2
Task 3
Solution
Android Kotlin
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: android.os.Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      val viewModel = GreetingViewModel()
      GreetingScreen(viewModel)
    }
  }
}

// UseCase class that simulates fetching a greeting message
class FetchGreetingUseCase {
  suspend operator fun invoke(): String {
    delay(1000) // simulate network or computation delay
    return "Hello from Use Case!"
  }
}

// ViewModel that uses the UseCase and exposes UI state
class GreetingViewModel : ViewModel() {
  private val useCase = FetchGreetingUseCase()

  var greeting by mutableStateOf("")
    private set
  var isLoading by mutableStateOf(false)
    private set

  fun fetchGreeting() {
    viewModelScope.launch {
      isLoading = true
      greeting = useCase()
      isLoading = false
    }
  }
}

@Composable
fun GreetingScreen(viewModel: GreetingViewModel) {
  val greeting = viewModel.greeting
  val isLoading = viewModel.isLoading

  Column(
    modifier = Modifier
      .fillMaxSize()
      .padding(16.dp),
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally
  ) {
    Text(text = "Greeting:", style = MaterialTheme.typography.titleMedium)
    Spacer(modifier = Modifier.height(8.dp))
    TextField(
      value = greeting,
      onValueChange = {},
      readOnly = true,
      modifier = Modifier.fillMaxWidth(),
      placeholder = { Text("[__________________]") },
      singleLine = true
    )
    Spacer(modifier = Modifier.height(16.dp))
    if (isLoading) {
      CircularProgressIndicator()
    } else {
      Button(onClick = { viewModel.fetchGreeting() }) {
        Text("Fetch Greeting")
      }
    }
  }
}

This example shows a simple Use Case pattern in Android with Kotlin and Jetpack Compose.

The FetchGreetingUseCase class simulates a task that takes time, like fetching data from the internet, by delaying for 1 second and then returning a greeting string.

The GreetingViewModel holds the UI state: the greeting text and a loading flag. It calls the Use Case inside a coroutine to keep the UI responsive.

The GreetingScreen composable displays the greeting in a read-only text field, shows a loading spinner while waiting, and has a button to start fetching the greeting.

This pattern separates business logic (Use Case) from UI logic (ViewModel and Composable), making the code easier to test and maintain.

Final Result
Completed Screen
-------------------------
| Simple Use Case Demo   |
|-----------------------|
|                       |
|  Greeting:            |
|  Hello from Use Case! |
|                       |
|  [Fetch Greeting]     |
|                       |
-------------------------
User taps 'Fetch Greeting' button.
Loading spinner appears for 1 second.
Greeting text updates to 'Hello from Use Case!'.
Button reappears to allow fetching again.
Stretch Goal
Add error handling to the Use Case and show an error message on the screen if fetching fails.
💡 Hint
Modify the Use Case to throw an exception sometimes. Catch it in ViewModel and expose an error message state to the UI.

Practice

(1/5)
1. What is the main purpose of a use case (interactor) in Android app development?
easy
A. To organize app actions and separate business logic from UI
B. To design the app's user interface layout
C. To handle database migrations automatically
D. To manage app permissions and security

Solution

  1. Step 1: Understand the role of use cases

    Use cases focus on organizing the app's business logic and actions clearly.
  2. Step 2: Differentiate from UI and other concerns

    They separate this logic from the user interface and other layers like database or security.
  3. Final Answer:

    To organize app actions and separate business logic from UI -> Option A
  4. Quick Check:

    Use cases = organize logic separate from UI [OK]
Hint: Use cases handle app actions, not UI or database [OK]
Common Mistakes:
  • Confusing use cases with UI components
  • Thinking use cases manage database directly
  • Assuming use cases handle permissions
2. Which Kotlin syntax correctly defines a simple use case class with an invoke operator function?
easy
A. class GetUserUseCase { fun call(id: Int): User { /*...*/ } }
B. class GetUserUseCase { operator fun invoke(id: Int): User { /*...*/ } }
C. fun GetUserUseCase(id: Int): User { /*...*/ }
D. object GetUserUseCase { fun invoke(id: Int): User { /*...*/ } }

Solution

  1. Step 1: Identify correct class and operator syntax

    Use cases are often classes with an operator fun invoke to call them like functions.
  2. Step 2: Check each option's syntax

    class GetUserUseCase { operator fun invoke(id: Int): User { /*...*/ } } correctly defines a class with operator fun invoke. fun GetUserUseCase(id: Int): User { /*...*/ } is a function, not a class. class GetUserUseCase { fun call(id: Int): User { /*...*/ } } uses fun call, not invoke. object GetUserUseCase { fun invoke(id: Int): User { /*...*/ } } uses object but lacks operator keyword.
  3. Final Answer:

    class GetUserUseCase { operator fun invoke(id: Int): User { /*...*/ } } -> Option B
  4. Quick Check:

    Use case class with operator invoke = class GetUserUseCase { operator fun invoke(id: Int): User { /*...*/ } } [OK]
Hint: Use operator fun invoke inside class for use cases [OK]
Common Mistakes:
  • Defining use case as a simple function instead of class
  • Missing operator keyword for invoke function
  • Using object without operator fun invoke
3. Given this use case code snippet, what will be printed?
class AddNumbersUseCase {
  operator fun invoke(a: Int, b: Int): Int = a + b
}

fun main() {
  val add = AddNumbersUseCase()
  println(add(3, 4))
}
medium
A. 7
B. 34
C. Error: invoke requires one parameter
D. null

Solution

  1. Step 1: Understand operator fun invoke with two parameters

    The invoke function takes two Ints and returns their sum.
  2. Step 2: Call add(3, 4) executes invoke(3, 4) returning 7

    Printing this result outputs 7.
  3. Final Answer:

    7 -> Option A
  4. Quick Check:

    3 + 4 = 7 [OK]
Hint: Invoke operator calls function with parameters directly [OK]
Common Mistakes:
  • Thinking parameters concatenate as strings
  • Assuming invoke only takes one parameter
  • Expecting null or error output
4. Identify the error in this use case implementation:
class MultiplyUseCase {
  operator fun invoke(a: Int, b: Int): Int {
    return a * b
  }
}

fun main() {
  val multiply = MultiplyUseCase()
  println(multiply.invoke(5))
}
medium
A. println cannot print Int values
B. Missing return statement in invoke function
C. MultiplyUseCase should be an object, not a class
D. invoke function called with wrong number of arguments

Solution

  1. Step 1: Check invoke function parameters

    invoke expects two Int parameters: a and b.
  2. Step 2: Analyze call multiply.invoke(5)

    Only one argument is passed, causing a compile-time error for wrong argument count.
  3. Final Answer:

    invoke function called with wrong number of arguments -> Option D
  4. Quick Check:

    invoke needs 2 args, call has 1 [OK]
Hint: Check function parameter count matches call arguments [OK]
Common Mistakes:
  • Ignoring parameter count mismatch
  • Thinking classes must be objects for use cases
  • Assuming println can't print Int
5. You want to create a use case that fetches user details and then logs the action. Which approach best follows use case principles?
hard
A. Put fetching logic in UI code and logging in a separate utility class
B. Combine fetching, logging, and UI updates all inside the use case invoke function
C. Create a use case class that fetches user data and calls a logger inside invoke
D. Use a use case only for logging, and fetch data directly in the UI

Solution

  1. Step 1: Understand use case responsibility

    Use cases should handle business logic like fetching and related actions such as logging.
  2. Step 2: Evaluate options for separation and clarity

    Create a use case class that fetches user data and calls a logger inside invoke keeps fetching and logging together in use case, separating UI concerns. Others mix UI and logic or split related logic incorrectly.
  3. Final Answer:

    Create a use case class that fetches user data and calls a logger inside invoke -> Option C
  4. Quick Check:

    Use case = business logic + related actions [OK]
Hint: Keep related logic inside use case, UI handles display only [OK]
Common Mistakes:
  • Mixing UI code with business logic
  • Splitting related logic across unrelated classes
  • Using use case only for one small task
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard