DEV Community

Cover image for Handling In-App Updates Gracefully So Users Never Get Stuck on Old Schemas
DEVANSHU PATIL
DEVANSHU PATIL

Posted on

Handling In-App Updates Gracefully So Users Never Get Stuck on Old Schemas

Handling In-App Updates Gracefully So Users Never Get Stuck on Old Schemas

Few things are more frustrating to a mobile user than being forcibly blocked by an update modal.

Imagine you are standing at a checkout counter, or reconciling an urgent bank balance. You open your finance app to log an expense, and the screen is held hostage by a full-screen, un-dismissible popup: "Update Required! Tap here to open Google Play."

You tap update, wait for a 40MB download over a weak cellular connection, watch the installation progress, and by the time the app re-opens, you have forgotten the transaction details.

Forced immediate updates alienate users. But ignoring updates completely leaves users running outdated schemas, missing critical bug fixes, or lacking security patches.

In FinLedger (commit 90c352f), we solved this by implementing the Google Play In-App Updates API using a non-intrusive Flexible Download workflow.

Here is how that lifecycle is engineered.

Immediate vs. Flexible Updates

The Google Play Core In-App Update API provides two distinct user flows:

flowchart TD
    subgraph UpdateStrategies["Google Play Update Strategies"]
        direction TB
        Immediate["1. Immediate Update (Blocking):
Full-screen modal. Blocks UI completely. Forces download & install before app can be used."]
        Flexible["2. Flexible Update (Non-Intrusive):
Prompts user once. Downloads in the background while user continues using the app. Shows subtle restart banner when ready."]
    end

When to Use Immediate Updates

Immediate updates should be reserved exclusively for critical emergencies:

  • A severe security vulnerability where un-patched versions cannot safely execute.
  • A breaking API change or database migration bug where continuing to use the older version causes irrevocable data corruption.

Why Financial Apps Need Flexible Updates

For routine feature updates, performance improvements, and minor bug fixes, Flexible Updates are vastly superior:

  • The user is shown a standard Google Play bottom sheet asking if they wish to download the update.
  • If they accept, the update downloads silently in the background while they continue creating accounts, logging transactions, or reviewing budgets.
  • If they decline or are busy, the prompt dismisses gracefully and does not nag them again during that session.

The Flexible Update Lifecycle State Machine

Implementing Flexible Updates properly requires managing an asynchronous state machine:

stateDiagram-v2
    [*] --> CheckAvailability : App Launch
    CheckAvailability --> NoUpdate : Update Not Available
    CheckAvailability --> UpdateAvailable : Update Available (AppUpdateInfo)

    UpdateAvailable --> PromptUser : Request Flexible Flow
    PromptUser --> UserDeclined : User Dismisses
    PromptUser --> Downloading : User Accepts

    Downloading --> Downloading : Background Progress
    Downloading --> Downloaded : InstallStatus.DOWNLOADED

    Downloaded --> ShowRestartBanner : Display Persistent In-App Snack
    ShowRestartBanner --> Restarting : User Taps 'Restart'
    Restarting --> [*] : completeUpdate()

1. Checking Availability

On cold app startup, the UpdateManager queries the Google Play Store client:

  • It checks appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE.
  • It verifies that the update is allowed to run flexibly: appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE).

2. Background Download Monitoring

Once the user accepts the flexible update prompt:

  • An InstallStateUpdatedListener monitors background progress.
  • As the APK chunks download, the app remains fully responsive.
  • When the download completes, the listener receives InstallStatus.DOWNLOADED.

3. The Non-Intrusive Restart Banner

When an update finishes downloading, Android does not forcefully kill the app to install it. That would risk corrupting an active SQLite transaction!

Instead, FinLedger surfaces a subtle, high-contrast banner at the top of the screen:

  • "An update has been downloaded. Restart to apply the latest improvements."
  • The banner includes a Restart Now action button and a dismiss option.
  • When the user finishes logging their transactions and taps Restart, the app cleanly flushes its Room database connections, closes open cursors, and invokes appUpdateManager.completeUpdate().

Google Play seamlessly restarts the application with the new version running in less than two seconds.

Handling the Resume Edge Case

A common developer bug with flexible updates occurs when an update finishes downloading while the app is minimized in the background.

When the user re-opens the app hours later, the listener never fired while the app was asleep.

To resolve this:

  • FinLedger re-checks appUpdateManager.appUpdateInfo in MainActivity.onResume().
  • If the status is already InstallStatus.DOWNLOADED, the restart banner is immediately mounted on screen, ensuring the user is notified even if the download completed while the phone was locked.

Key Takeaway

Respecting user autonomy extends to how you ship software updates.

By implementing Google Play Flexible In-App Updates with non-intrusive background downloads and explicit restart controls, FinLedger keeps users on the latest, most secure build without ever interrupting their financial workflow.


FinLedger is a privacy-first, offline-first personal finance application for Android that models bank accounts, credit cards, and cash without double-counting.

Explore FinLedger on Google Play: https://play.google.com/store/apps/details?id=com.devanshufinance.app

Top comments (0)