Android Development
File Download
ProgressDialog
Coding Tutorials
Android Applications

Download a file with Android, and showing the progress in a ProgressDialog

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Downloading files on Android should run off the main thread and provide clear progress feedback to users. The historical pattern used ProgressDialog, but modern Android apps usually prefer in-layout progress indicators, notifications, or foreground services. If you still maintain legacy code, you can support ProgressDialog carefully while planning a migration path.

Legacy Pattern with ProgressDialog

ProgressDialog was commonly paired with background work to show byte progress. It still appears in older codebases, though it is deprecated in modern UI guidance.

A legacy Java-style implementation structure:

java
1ProgressDialog dialog = new ProgressDialog(this);
2dialog.setTitle("Downloading...");
3dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
4dialog.setMax(100);
5dialog.show();

Background task then updates progress and dismisses dialog on completion. This approach works for older apps but is not ideal for modern lifecycle-aware architectures.

Modern Download Approach with Kotlin Coroutines

A better pattern is:

  • execute network stream in Dispatchers.IO
  • emit progress updates to UI state
  • render progress using a ProgressBar

Example using HttpURLConnection and coroutine context switching:

kotlin
1import kotlinx.coroutines.Dispatchers
2import kotlinx.coroutines.withContext
3import java.io.File
4import java.io.FileOutputStream
5import java.net.HttpURLConnection
6import java.net.URL
7
8suspend fun downloadFile(
9    url: String,
10    outFile: File,
11    onProgress: (Int) -> Unit
12) = withContext(Dispatchers.IO) {
13    val connection = URL(url).openConnection() as HttpURLConnection
14    connection.connect()
15
16    val total = connection.contentLength
17    connection.inputStream.use { input ->
18        FileOutputStream(outFile).use { output ->
19            val buffer = ByteArray(8192)
20            var downloaded = 0L
21            while (true) {
22                val read = input.read(buffer)
23                if (read == -1) break
24                output.write(buffer, 0, read)
25                downloaded += read
26                if (total > 0) {
27                    val percent = ((downloaded * 100) / total).toInt()
28                    onProgress(percent)
29                }
30            }
31            output.flush()
32        }
33    }
34
35    connection.disconnect()
36}

This keeps network and disk work off the main thread while reporting progress safely.

UI Integration Without ProgressDialog

In an activity or fragment, update a visible progress widget.

kotlin
1lifecycleScope.launch {
2    try {
3        progressBar.isIndeterminate = false
4        progressBar.progress = 0
5
6        downloadFile(
7            url = "https://example.com/file.zip",
8            outFile = File(cacheDir, "file.zip"),
9            onProgress = { percent ->
10                runOnUiThread { progressBar.progress = percent }
11            }
12        )
13
14        Toast.makeText(this@MainActivity, "Download complete", Toast.LENGTH_SHORT).show()
15    } catch (e: Exception) {
16        Toast.makeText(this@MainActivity, "Download failed: ${e.message}", Toast.LENGTH_LONG).show()
17    }
18}

This pattern is lifecycle-friendlier and aligns with modern Android UX.

Large or Long Downloads

If download duration can exceed app foreground lifetime, use system-aware tools.

Preferred options:

  • DownloadManager for simple managed downloads
  • foreground service for custom persistent transfer logic
  • WorkManager for guaranteed deferred execution

Using these options avoids lost progress when activity is destroyed.

Storage and Permission Considerations

Modern Android storage model differs from legacy external storage workflows. For app-private files, no storage permission is needed in most cases.

For public media or shared documents, use scoped storage APIs and platform-appropriate intents.

Always validate:

  • destination path exists and writable
  • enough free disk space
  • checksum or signature if file integrity is critical

These checks prevent partial or corrupted output from being treated as success.

Migrating from AsyncTask and ProgressDialog

If your app still uses AsyncTask and ProgressDialog, migration steps are straightforward:

  1. replace AsyncTask with coroutines or WorkManager
  2. replace ProgressDialog with in-layout progress UI or notifications
  3. move download logic to a lifecycle-aware component
  4. add cancellation handling and cleanup logic
  5. add tests for resume, failure, and network loss

Incremental migration is safer than rewriting download features in one release.

Common Pitfalls

  • Performing download work on the main thread and freezing the UI.
  • Using deprecated dialog-only progress UX without lifecycle handling.
  • Ignoring cancellation when user leaves screen or app process is reclaimed.
  • Writing directly to fragile paths without storage model checks.
  • Treating successful network response as valid file without integrity validation.

Summary

  • File downloads should be asynchronous and lifecycle-aware in Android.
  • ProgressDialog is a legacy pattern and should be phased out in new code.
  • Coroutines with explicit progress callbacks offer clear modern control flow.
  • For long-running downloads, prefer system-managed components such as DownloadManager or WorkManager.
  • Reliable download features include storage checks, cancellation support, and integrity validation.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.