import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class AsyncDemoActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
var isLoading by remember { mutableStateOf(false) }
var resultText by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
Button(onClick = {
isLoading = true
resultText = ""
lifecycleScope.launch {
delay(2000) // Simulate async work
resultText = "Data fetched successfully!"
isLoading = false
}
}) {
Text("Fetch Data")
}
if (isLoading) {
CircularProgressIndicator(modifier = Modifier.padding(top = 16.dp))
} else {
Text(text = "Result: $resultText", modifier = Modifier.padding(top = 16.dp))
}
}
}
}
}
}This example uses Kotlin coroutines to simplify asynchronous programming. When the user taps the 'Fetch Data' button, a coroutine starts using lifecycleScope.launch. Inside the coroutine, delay(2000) simulates a network call or long-running task without blocking the main thread.
The UI shows a loading spinner while waiting. After the delay, the result text updates to show the fetched data. Because coroutines allow writing asynchronous code sequentially, it is easier to read and maintain compared to callbacks or threads.
Using mutableStateOf and Compose's state management, the UI automatically updates when the loading state or result changes, keeping the app responsive and smooth.