------------------------- | Simple Use Case Demo | |-----------------------| | | | Greeting: | | [__________________] | | | | [Fetch Greeting] | | | -------------------------
Use cases / Interactors in Android Kotlin - Mini App: Build & Ship
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 }
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.
------------------------- | Simple Use Case Demo | |-----------------------| | | | Greeting: | | Hello from Use Case! | | | | [Fetch Greeting] | | | -------------------------
Practice
Solution
Step 1: Understand the role of use cases
Use cases focus on organizing the app's business logic and actions clearly.Step 2: Differentiate from UI and other concerns
They separate this logic from the user interface and other layers like database or security.Final Answer:
To organize app actions and separate business logic from UI -> Option AQuick Check:
Use cases = organize logic separate from UI [OK]
- Confusing use cases with UI components
- Thinking use cases manage database directly
- Assuming use cases handle permissions
Solution
Step 1: Identify correct class and operator syntax
Use cases are often classes with an operator fun invoke to call them like functions.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.Final Answer:
class GetUserUseCase { operator fun invoke(id: Int): User { /*...*/ } } -> Option BQuick Check:
Use case class with operator invoke = class GetUserUseCase { operator fun invoke(id: Int): User { /*...*/ } } [OK]
- Defining use case as a simple function instead of class
- Missing operator keyword for invoke function
- Using object without operator fun invoke
class AddNumbersUseCase {
operator fun invoke(a: Int, b: Int): Int = a + b
}
fun main() {
val add = AddNumbersUseCase()
println(add(3, 4))
}Solution
Step 1: Understand operator fun invoke with two parameters
The invoke function takes two Ints and returns their sum.Step 2: Call add(3, 4) executes invoke(3, 4) returning 7
Printing this result outputs 7.Final Answer:
7 -> Option AQuick Check:
3 + 4 = 7 [OK]
- Thinking parameters concatenate as strings
- Assuming invoke only takes one parameter
- Expecting null or error output
class MultiplyUseCase {
operator fun invoke(a: Int, b: Int): Int {
return a * b
}
}
fun main() {
val multiply = MultiplyUseCase()
println(multiply.invoke(5))
}Solution
Step 1: Check invoke function parameters
invoke expects two Int parameters: a and b.Step 2: Analyze call multiply.invoke(5)
Only one argument is passed, causing a compile-time error for wrong argument count.Final Answer:
invoke function called with wrong number of arguments -> Option DQuick Check:
invoke needs 2 args, call has 1 [OK]
- Ignoring parameter count mismatch
- Thinking classes must be objects for use cases
- Assuming println can't print Int
Solution
Step 1: Understand use case responsibility
Use cases should handle business logic like fetching and related actions such as logging.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.Final Answer:
Create a use case class that fetches user data and calls a logger inside invoke -> Option CQuick Check:
Use case = business logic + related actions [OK]
- Mixing UI code with business logic
- Splitting related logic across unrelated classes
- Using use case only for one small task
Ready to prove it?
Pass the test and this pattern moves unknown
