Programmatically Check the Network Speed in Android
Last Updated :
04 Apr, 2025
Network speed can be defined as the total number of packets being exchanged by the client and the server per second, usually calculated in Megabits per second(Mbps). A bit is either a 0 or 1. 1 Megabit implies 1 Million bits. Usually, packet size depends on the protocol and various other factors and usually ranges on a vast scale. In this article, a program is implemented that fetches us Upload and Download speeds with the server. Note that the program is successful when the device is connected to a network.
This program could be used for research as well as for optimization:
- Research: one could derive the content and the available speeds to correlate the network dependency.
- Optimization: one could continuously monitor the speed and context, to avoid the connection when not required or reduce the quality of a video being broadcasted depending upon the current speeds.
Approach:
Step 1: Create an Empty activity in Android Studio.
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio.
Check if the primary language selected is Kotlin.
Step 2: Go to the AndroidManifest.xml file and add Permissions
AndroidManifest.xml:
XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Application"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Step 3: In the activity_main.xml, add a button. Below is the code for the same.
activity_main.xml:
XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:background="@color/white"
tools:context=".MainActivity">
<androidx.cardview.widget.CardView
android:id="@+id/cardViewSpeed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Speed Test Results"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="8dp" />
<TextView
android:id="@+id/downloadSpeed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/data_download"
android:textSize="16sp"
android:layout_marginTop="4dp" />
<TextView
android:id="@+id/uploadSpeed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/data_upload"
android:textSize="16sp"
android:layout_marginTop="4dp" />
<TextView
android:id="@+id/quality"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/data_quality"
android:textSize="16sp"
android:layout_marginTop="4dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/btnStartTest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="Start Speed Test"
android:textAllCaps="false"
android:padding="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cardViewSpeed" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnStartTest" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/data_status"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar" />
</androidx.constraintlayout.widget.ConstraintLayout>
Design UI:
Step 4: Required a class file to calculate Network Speed for the Application.
In this Program we are checking on the a site to checking the response to calculate the speed from it.
SpeedChecker.kt:
Kotlin
package com.gfg.application
import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.InputStream
import java.io.OutputStream
import java.net.HttpURLConnection
import java.net.URL
import kotlin.math.roundToInt
class SpeedChecker(private val context: Context) {
// Measure download speed (returns speed in Mbps)
suspend fun measureDownloadSpeed(testUrl: String = "https://www.google.com"): Double = withContext(Dispatchers.IO) {
try {
val startTime = System.currentTimeMillis()
val connection = URL(testUrl).openConnection() as HttpURLConnection
connection.requestMethod = "GET"
connection.connectTimeout = 10000
connection.readTimeout = 10000
connection.connect()
val inputStream: InputStream = connection.inputStream
val buffer = ByteArray(8192)
var bytesRead: Int
var totalBytesRead = 0L
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
totalBytesRead += bytesRead
// Stop test after 10 seconds to avoid excessive data usage
if (System.currentTimeMillis() - startTime > 10000) break
}
val endTime = System.currentTimeMillis()
// Convert to seconds
val duration = (endTime - startTime) / 1000.0
inputStream.close()
connection.disconnect()
// Calculate speed in Mbps (Megabits per second)
val speedMbps = ((totalBytesRead * 8) / 1000000.0) / duration
(speedMbps * 100).roundToInt() / 100.0
// Round to 2 decimal places
} catch (e: Exception) {
e.printStackTrace()
0.0
}
}
// Measure upload speed (returns speed in Mbps)
suspend fun measureUploadSpeed(testUrl: String = "https://httpbin.org/post"): Double = withContext(Dispatchers.IO) {
try {
val dataSize = 1000000 // 1MB
// Fill with 'a'
val data = ByteArray(dataSize) { 0x61 }
val startTime = System.currentTimeMillis()
val connection = URL(testUrl).openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.doOutput = true
connection.connectTimeout = 10000
connection.readTimeout = 10000
connection.connect()
val outputStream: OutputStream = connection.outputStream
outputStream.write(data)
outputStream.flush()
outputStream.close()
// Read response to complete the request
val inputStream: InputStream = connection.inputStream
val buffer = ByteArray(8192)
while (inputStream.read(buffer) != -1) { /* Just consuming the response */ }
val endTime = System.currentTimeMillis()
// Convert to seconds
val duration = (endTime - startTime) / 1000.0
inputStream.close()
connection.disconnect()
// Calculate speed in Mbps (Megabits per second)
val speedMbps = ((dataSize * 8) / 1000000.0) / duration
(speedMbps * 100).roundToInt() / 100.0
// Round to 2 decimal places
} catch (e: Exception) {
e.printStackTrace()
0.0
}
}
// Get network quality based on download speed
fun getNetworkQuality(downloadSpeedMbps: Double): String {
return when {
downloadSpeedMbps <= 0 -> "No Connection"
downloadSpeedMbps < 1 -> "Poor"
downloadSpeedMbps < 5 -> "Fair"
downloadSpeedMbps < 10 -> "Good"
downloadSpeedMbps < 30 -> "Very Good"
else -> "Excellent"
}
}
}
Explanation of the above Program:
- Downloads data from the URL and then measures the time of Download/Download Speed.
- After that we are sending 1MB dummy data to calculate the Upload speed.
Step 5: Modifying the MainActivity File
In the MainActivity.kt, add the below code. setOnClickListener is added with the button, which when clicked shows the upload speed and download speed as a toast on the screen.
MainActivity.kt:
Kotlin
package com.gfg.application
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private lateinit var networkSpeedChecker: SpeedChecker
// UI elements
private lateinit var tvDownloadSpeed: TextView
private lateinit var tvUploadSpeed: TextView
private lateinit var tvQuality: TextView
private lateinit var tvStatus: TextView
private lateinit var btnStartTest: Button
private lateinit var progressBar: ProgressBar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize NetworkSpeedChecker
networkSpeedChecker = SpeedChecker(this)
// Bind UI elements
tvDownloadSpeed = findViewById(R.id.downloadSpeed)
tvUploadSpeed = findViewById(R.id.uploadSpeed)
tvQuality = findViewById(R.id.quality)
tvStatus = findViewById(R.id.status)
btnStartTest = findViewById(R.id.btnStartTest)
progressBar = findViewById(R.id.progressBar)
// Set up button click listener
btnStartTest.setOnClickListener {
startSpeedTest()
}
}
private fun startSpeedTest() {
// Update UI to show test is running
progressBar.visibility = View.VISIBLE
btnStartTest.isEnabled = false
tvStatus.text = getString(R.string.testing_network_speed)
// Run speed test in background
lifecycleScope.launch {
// Measure download speed
tvStatus.text = getString(R.string.measuring_download_speed)
val downloadSpeed = networkSpeedChecker.measureDownloadSpeed()
// Measure upload speed
tvStatus.text = getString(R.string.measuring_upload_speed)
val uploadSpeed = networkSpeedChecker.measureUploadSpeed()
// Get quality assessment
val quality = networkSpeedChecker.getNetworkQuality(downloadSpeed)
// Update UI with results
runOnUiThread {
tvDownloadSpeed.text = getString(R.string.download_speed, downloadSpeed)
tvUploadSpeed.text = getString(R.string.upload_speed, uploadSpeed)
tvQuality.text = getString(R.string.network_quality, quality)
// Reset UI state
progressBar.visibility = View.GONE
btnStartTest.isEnabled = true
tvStatus.text = getString(R.string.test_completed)
}
}
}
}
To check the whole application code - Click Here
Demo Video: