UI threading
asynchronous operations
performance optimization
user experience
UI refresh

How to let the UI refresh during a long running UI operation

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If a long-running operation is executing on the UI thread, the UI cannot repaint smoothly no matter how often you ask it to refresh. The real fix is not to "force redraws" during the work. It is to move the expensive work off the UI thread, keep the main thread free to process events, and publish progress back in small UI-safe updates.

Why the UI Freezes

Most UI frameworks use a main event loop. That thread is responsible for:

  • handling input
  • running paint or layout work
  • dispatching event callbacks

If you run a heavy loop on that same thread, the event loop cannot process redraw requests. Calling refresh(), invalidate(), or similar APIs inside the heavy operation often does not help because the thread is still busy.

The fix is architectural: separate computation from presentation.

A Simple Example in C#

The pattern below runs expensive work on a background thread and reports progress back to the UI:

csharp
1private async void StartButton_Click(object sender, EventArgs e)
2{
3    progressBar.Value = 0;
4    statusLabel.Text = "Working...";
5
6    await Task.Run(() =>
7    {
8        for (int i = 1; i <= 100; i++)
9        {
10            Thread.Sleep(20);
11
12            Invoke(() =>
13            {
14                progressBar.Value = i;
15                statusLabel.Text = $"Step {i}/100";
16            });
17        }
18    });
19
20    statusLabel.Text = "Done";
21}

The important point is that the loop does not block the UI thread. The UI thread remains free to paint the progress bar and respond to events.

The Same Principle in Other UI Frameworks

The framework-specific API differs, but the rule is stable:

  • do heavy work in a background task, worker thread, or coroutine
  • marshal small updates back to the UI thread

Examples include:

  • 'async and await in .NET UI apps'
  • coroutines on Android
  • worker threads or asynchronous tasks in desktop apps
  • non-blocking work plus state updates in web interfaces

The framework changes. The event-loop principle does not.

Progress Matters More Than Forced Refresh

Users tolerate waiting much better when the UI explains what is happening. Good progress reporting includes:

  • a spinner for unknown duration
  • a progress bar for measurable work
  • clear status text

This is often more valuable than chasing repaint tricks. A smoothly updating spinner driven by background work is the right experience. A blocked UI that occasionally repaints is still a bad experience.

Chunking Work Can Also Help

If the operation truly must remain on the main thread in small pieces, break it into chunks and yield between them so the event loop can process pending paint operations. That is still second-best compared with moving the work off the UI thread, but it can help with incremental tasks such as DOM-heavy rendering or staged layout updates.

The key is that each chunk must be short. A thousand tiny pauses are better than one giant block.

Common Pitfalls

The biggest mistake is trying to call repaint APIs from inside a long synchronous UI loop and expecting the screen to stay responsive. If the event loop is blocked, redraw requests cannot run.

Another problem is moving the work to a background thread but then touching UI widgets directly from that thread. Most UI toolkits require UI state changes to happen on the main thread.

Developers also sometimes report progress too frequently. Updating the UI thousands of times per second can create unnecessary overhead and make the app slower overall.

Finally, avoid fake progress when real progress can be measured. Users notice when the bar jumps randomly or stalls for long periods.

Summary

  • A blocked UI thread cannot repaint smoothly, no matter how often you request refreshes.
  • Move long-running work off the UI thread whenever possible.
  • Send progress updates back to the UI thread in small, safe increments.
  • Use chunking only when background execution is not practical.
  • Focus on responsiveness and progress reporting, not on redraw hacks.

Course illustration
Course illustration

All Rights Reserved.