0
0
Android Kotlinmobile~20 mins

launch and async builders in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Async Data Loader
This screen loads data asynchronously and shows loading status. It uses Kotlin coroutines with launch and async builders to fetch data in the background and update the UI when done.
Target UI
-------------------------
| Async Data Loader      |
|-----------------------|
| [Load Data]           |
|                       |
| Status: Idle          |
|                       |
| Data:                 |
|                       |
|                       |
-------------------------
Add a button labeled 'Load Data' that starts loading data asynchronously when tapped.
Use a coroutine launch builder to start the loading process.
Inside launch, use async builder to simulate fetching data with a delay.
Show 'Loading...' in the status text while data is loading.
When data is loaded, update the status to 'Data loaded' and display the fetched data below.
Handle coroutine scope properly to avoid leaks.
Starter Code
Android Kotlin
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.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.*

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      MaterialTheme {
        Surface(modifier = Modifier.padding(16.dp)) {
          AsyncDataLoaderScreen()
        }
      }
    }
  }
}

@Composable
fun AsyncDataLoaderScreen() {
  var status by remember { mutableStateOf("Idle") }
  var data by remember { mutableStateOf("") }

  // TODO: Add coroutine scope and implement button click to load data asynchronously

  Column {
    Button(onClick = { /* TODO: Start loading data */ }) {
      Text("Load Data")
    }
    Text("Status: $status", modifier = Modifier.padding(top = 16.dp))
    Text("Data: $data", modifier = Modifier.padding(top = 8.dp))
  }
}
Task 1
Task 2
Task 3
Task 4
Task 5
Solution
Android Kotlin
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.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.*

class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      MaterialTheme {
        Surface(modifier = Modifier.padding(16.dp)) {
          AsyncDataLoaderScreen()
        }
      }
    }
  }
}

@Composable
fun AsyncDataLoaderScreen() {
  var status by remember { mutableStateOf("Idle") }
  var data by remember { mutableStateOf("") }
  val scope = rememberCoroutineScope()

  Column {
    Button(onClick = {
      scope.launch {
        status = "Loading..."
        val deferredData = async {
          delay(2000) // Simulate network or heavy work
          "Here is your loaded data!"
        }
        data = deferredData.await()
        status = "Data loaded"
      }
    }) {
      Text("Load Data")
    }
    Text("Status: $status", modifier = Modifier.padding(top = 16.dp))
    Text("Data: $data", modifier = Modifier.padding(top = 8.dp))
  }
}

We use rememberCoroutineScope() to get a coroutine scope tied to the composable lifecycle. When the user taps the 'Load Data' button, we launch a coroutine in this scope.

Inside the coroutine, we first update the status to 'Loading...'. Then we use async builder to simulate fetching data with a 2-second delay. This runs concurrently and returns a deferred result.

We await() the result from async, then update the data state and set status to 'Data loaded'. This updates the UI automatically.

This approach keeps the UI responsive and shows loading feedback while data is fetched asynchronously.

Final Result
Completed Screen
-------------------------
| Async Data Loader      |
|-----------------------|
| [Load Data]           |
|                       |
| Status: Data loaded   |
|                       |
| Data:                 |
| Here is your loaded   |
| data!                 |
-------------------------
User taps 'Load Data' button.
Status text changes to 'Loading...'.
After 2 seconds, status changes to 'Data loaded'.
Fetched data text appears below status.
Stretch Goal
Add a cancel button to stop loading if user changes their mind.
💡 Hint
Use a Job reference to cancel the coroutine launched in the scope.