Android Development
ProgressDialog
User Interface
Android App Design
Mobile Development

Show ProgressDialog Android

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

ProgressDialog was once the standard Android way to show blocking progress, but it is now a legacy API and not the recommended choice for modern apps. If you are maintaining old code, you may still need to understand how it works. For new code, an inline ProgressBar, a custom dialog, or a loading state driven by your view model is the better design.

The Legacy ProgressDialog Pattern

Older Android code often looked like this:

kotlin
1import android.app.ProgressDialog
2import android.os.Bundle
3import androidx.appcompat.app.AppCompatActivity
4
5class MainActivity : AppCompatActivity() {
6    private var progressDialog: ProgressDialog? = null
7
8    override fun onCreate(savedInstanceState: Bundle?) {
9        super.onCreate(savedInstanceState)
10
11        progressDialog = ProgressDialog(this).apply {
12            setMessage("Loading...")
13            setCancelable(false)
14        }
15    }
16
17    private fun showLoading() {
18        progressDialog?.show()
19    }
20
21    private fun hideLoading() {
22        progressDialog?.dismiss()
23    }
24}

This worked, but it encouraged modal, blocking UI and could easily create leaks or lifecycle bugs if the activity rotated or finished while the dialog was still showing.

Why It Fell Out of Favor

A blocking spinner dialog is rarely the best user experience. It interrupts the whole screen, hides context, and often communicates less clearly than inline loading states. On Android, the move away from ProgressDialog is really about UI architecture and lifecycle safety, not just API fashion.

Problems with the old pattern include:

  • dialog leaks on configuration change
  • awkward dismissal timing
  • inaccessible or unclear UX
  • difficulty modeling loading, success, and error as explicit UI state

Modern Approach: Inline ProgressBar

For most screens, keep the user on the screen and show loading inside the layout.

xml
1<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2    android:layout_width="match_parent"
3    android:layout_height="match_parent"
4    android:orientation="vertical">
5
6    <ProgressBar
7        android:id="@+id/progressBar"
8        android:layout_width="wrap_content"
9        android:layout_height="wrap_content"
10        android:visibility="gone" />
11
12</LinearLayout>

Then toggle visibility in code:

kotlin
1import android.os.Bundle
2import android.view.View
3import android.widget.ProgressBar
4import androidx.appcompat.app.AppCompatActivity
5
6class MainActivity : AppCompatActivity() {
7    private lateinit var progressBar: ProgressBar
8
9    override fun onCreate(savedInstanceState: Bundle?) {
10        super.onCreate(savedInstanceState)
11        setContentView(R.layout.activity_main)
12
13        progressBar = findViewById(R.id.progressBar)
14    }
15
16    private fun showLoading() {
17        progressBar.visibility = View.VISIBLE
18    }
19
20    private fun hideLoading() {
21        progressBar.visibility = View.GONE
22    }
23}

This is simpler, more lifecycle-friendly, and usually better for the user.

Use a Custom Dialog Only When the Interaction Truly Requires It

Sometimes you do want a modal loading dialog, for example during a short, blocking confirmation step. In that case, build it with modern dialog APIs and an embedded ProgressBar instead of relying on ProgressDialog.

kotlin
1import android.app.AlertDialog
2import android.os.Bundle
3import android.widget.ProgressBar
4import androidx.appcompat.app.AppCompatActivity
5
6class MainActivity : AppCompatActivity() {
7    private var loadingDialog: AlertDialog? = null
8
9    override fun onCreate(savedInstanceState: Bundle?) {
10        super.onCreate(savedInstanceState)
11
12        val progressBar = ProgressBar(this)
13        loadingDialog = AlertDialog.Builder(this)
14            .setTitle("Please wait")
15            .setView(progressBar)
16            .setCancelable(false)
17            .create()
18    }
19
20    private fun showLoading() {
21        loadingDialog?.show()
22    }
23
24    private fun hideLoading() {
25        loadingDialog?.dismiss()
26    }
27}

This still needs lifecycle care, but it avoids the deprecated API and makes the UI contract explicit.

Tie Loading to View State

The best long-term pattern is to drive progress UI from state, not from ad hoc calls scattered around network callbacks.

For example:

kotlin
1sealed class UiState {
2    data object Loading : UiState()
3    data object Content : UiState()
4    data class Error(val message: String) : UiState()
5}

When the screen state is Loading, show the spinner. When it is Content, hide it. This scales much better than manually calling show() and dismiss() from many places.

Indeterminate Versus Determinate Progress

Use an indeterminate spinner when you do not know how long the task will take. Use a determinate horizontal progress bar when you can measure progress meaningfully, such as file upload percentage.

For determinate progress:

xml
1<ProgressBar
2    style="?android:attr/progressBarStyleHorizontal"
3    android:layout_width="match_parent"
4    android:layout_height="wrap_content"
5    android:max="100"
6    android:progress="35" />

Picking the wrong kind of progress indicator makes the UI feel unreliable even when the code is correct.

Common Pitfalls

The biggest mistake is using a modal progress dialog for routine loading that should be shown inline. Another is forgetting that old ProgressDialog code is vulnerable to activity lifecycle issues such as rotation and destruction. Developers also often show an indeterminate spinner for long tasks that should report actual progress. Finally, loading UI that is not driven by screen state tends to become inconsistent and difficult to maintain.

Summary

  • 'ProgressDialog is a legacy Android pattern and should not be the default in modern apps.'
  • For most screens, use an inline ProgressBar instead of a blocking dialog.
  • If a modal experience is required, build it with a regular dialog and a ProgressBar.
  • Model loading as UI state rather than scattered show and dismiss calls.
  • Choose determinate progress only when you can report meaningful completion percentages.

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.