0
0
Android Kotlinmobile~20 mins

GET and POST requests in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: NetworkRequestScreen
This screen lets the user send GET and POST requests to a test API and shows the response.
Target UI
┌───────────────────────────────┐
│ Network Requests              │
├───────────────────────────────┤
│ [GET Data]                   │
│ Response:                    │
│ <empty area>                 │
│                               │
│ [POST Data]                  │
│ Enter message: [__________]  │
│ [Send POST]                  │
└───────────────────────────────┘
Add a button labeled 'GET Data' that fetches data from https://jsonplaceholder.typicode.com/posts/1 using a GET request.
Display the fetched JSON response text below the GET button.
Add a TextField for user input labeled 'Enter message'.
Add a button labeled 'Send POST' that sends the entered message as JSON to https://jsonplaceholder.typicode.com/posts using a POST request.
Display the server response from the POST request below the POST button.
Show loading indicators while requests are in progress.
Handle errors by showing a simple error message in the response area.
Starter Code
Android Kotlin
import android.os.Bundle
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.Modifier
import androidx.compose.ui.unit.dp

class NetworkRequestScreen : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      // TODO: Add UI and network request code here
    }
  }
}
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.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import javax.net.ssl.HttpsURLConnection

class NetworkRequestScreen : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      NetworkRequestContent()
    }
  }
}

@Composable
fun NetworkRequestContent() {
  var getResponse by remember { mutableStateOf("") }
  var postResponse by remember { mutableStateOf("") }
  var postMessage by remember { mutableStateOf("") }
  var isLoadingGet by remember { mutableStateOf(false) }
  var isLoadingPost by remember { mutableStateOf(false) }

  val coroutineScope = rememberCoroutineScope()

  Column(modifier = Modifier.padding(16.dp)) {
    Button(onClick = {
      isLoadingGet = true
      getResponse = ""
      coroutineScope.launch(Dispatchers.IO) {
        try {
          val url = URL("https://jsonplaceholder.typicode.com/posts/1")
          val connection = url.openConnection() as HttpURLConnection
          connection.requestMethod = "GET"
          connection.connectTimeout = 5000
          connection.readTimeout = 5000

          val responseCode = connection.responseCode
          if (responseCode == HttpsURLConnection.HTTP_OK) {
            val reader = BufferedReader(InputStreamReader(connection.inputStream))
            val response = reader.readText()
            reader.close()
            isLoadingGet = false
            getResponse = response
          } else {
            isLoadingGet = false
            getResponse = "Error: Response code $responseCode"
          }
          connection.disconnect()
        } catch (e: Exception) {
          isLoadingGet = false
          getResponse = "Error: ${e.message}"
        }
      }
    }) {
      Text("GET Data")
    }

    Spacer(modifier = Modifier.height(8.dp))

    if (isLoadingGet) {
      Text("Loading GET data...", style = MaterialTheme.typography.bodyMedium)
    } else {
      Text(getResponse, style = MaterialTheme.typography.bodyMedium)
    }

    Spacer(modifier = Modifier.height(24.dp))

    OutlinedTextField(
      value = postMessage,
      onValueChange = { postMessage = it },
      label = { Text("Enter message") },
      modifier = Modifier.fillMaxWidth()
    )

    Spacer(modifier = Modifier.height(8.dp))

    Button(onClick = {
      if (postMessage.isBlank()) {
        postResponse = "Please enter a message to send."
        return@Button
      }
      isLoadingPost = true
      postResponse = ""
      coroutineScope.launch(Dispatchers.IO) {
        try {
          val url = URL("https://jsonplaceholder.typicode.com/posts")
          val connection = url.openConnection() as HttpURLConnection
          connection.requestMethod = "POST"
          connection.setRequestProperty("Content-Type", "application/json; utf-8")
          connection.doOutput = true
          connection.connectTimeout = 5000
          connection.readTimeout = 5000

          val jsonInputString = "{\"title\": \"$postMessage\", \"body\": \"$postMessage\", \"userId\": 1}"

          connection.outputStream.use { os ->
            val input = jsonInputString.toByteArray(Charsets.UTF_8)
            os.write(input, 0, input.size)
          }

          val responseCode = connection.responseCode
          if (responseCode == HttpsURLConnection.HTTP_CREATED || responseCode == HttpsURLConnection.HTTP_OK) {
            val reader = BufferedReader(InputStreamReader(connection.inputStream))
            val response = reader.readText()
            reader.close()
            isLoadingPost = false
            postResponse = response
          } else {
            isLoadingPost = false
            postResponse = "Error: Response code $responseCode"
          }
          connection.disconnect()
        } catch (e: Exception) {
          isLoadingPost = false
          postResponse = "Error: ${e.message}"
        }
      }
    }) {
      Text("Send POST")
    }

    Spacer(modifier = Modifier.height(8.dp))

    if (isLoadingPost) {
      Text("Sending POST data...", style = MaterialTheme.typography.bodyMedium)
    } else {
      Text(postResponse, style = MaterialTheme.typography.bodyMedium)
    }
  }
}

This solution uses Jetpack Compose to build the UI with two buttons and a text field. It uses Kotlin coroutines to perform network requests off the main thread.

When the user taps 'GET Data', it sends a GET request to the test API and shows the JSON response or an error message.

When the user enters text and taps 'Send POST', it sends a POST request with JSON containing the message. The response or error is shown below.

Loading states show simple text indicators while waiting for network responses.

HttpURLConnection is used for simplicity and compatibility. The UI updates reactively with Compose state variables.

Final Result
Completed Screen
┌───────────────────────────────┐
│ Network Requests              │
├───────────────────────────────┤
│ [GET Data]                   │
│ Response:                    │
│ {                           │
│   "userId": 1,             │
│   "id": 1,                 │
│   "title": "...",         │
│   "body": "..."           │
│ }                           │
│                               │
│ [POST Data]                  │
│ Enter message: [Hello API!]  │
│ [Send POST]                  │
│ Response:                   │
│ {                           │
│   "id": 101,               │
│   "title": "Hello API!", │
│   "body": "Hello API!",  │
│   "userId": 1              │
│ }                           │
└───────────────────────────────┘
Tap 'GET Data' button triggers a GET request and shows JSON response below.
Enter text in the input field and tap 'Send POST' to send POST request and show response.
Loading text appears while waiting for network responses.
Error messages appear if network fails.
Stretch Goal
Add a pull-to-refresh gesture to reload the GET data.
💡 Hint
Use SwipeRefresh from accompanist library or Compose's built-in pull refresh to trigger the GET request again.