Skip to content
Writing

Android

Sample title — Keeping an Android app useful offline

How I structure local data and sync so the app keeps working on a weak connection, and what I would do differently next time.

Quvonchbek Saydullayev · [Date] · 2 min read

Sample article — placeholder text
On this page

Most of the apps I build are used in places where the connection is not reliable. That changes the architecture more than any other requirement: the phone has to be the source of truth, and the server becomes a place to synchronise with, not to ask.

Local data first

Every screen reads from the local database and only from it. The network layer never renders UI directly; it writes into the same tables the UI observes. This sounds obvious until you meet a screen that “just needs one live value” — that one screen is where offline support usually breaks.

A small rule that helps: the repository exposes Flow objects, never suspend functions that fetch. Fetching is the sync worker’s job.

Sync as a background job

Sync runs in a CoroutineWorker with a network constraint. Pushing before pulling avoids overwriting a local edit with stale server data.

class SyncWorker(ctx: Context, params: WorkerParameters)
  : CoroutineWorker(ctx, params) {
  override suspend fun doWork(): Result {
    // Push local changes first, then pull.
    return try { repo.push(); repo.pull(); Result.success() }
    catch (e: IOException) { Result.retry() }
  }
}

Handling conflicts

  • Last-write-wins for simple fields, with a timestamp from the device.
  • Merge for lists, so two people adding items do not erase each other.
  • A visible “needs review” state when neither rule applies.

The goal is not to make conflicts impossible — it is to make them visible and cheap to fix.

Testing on bad networks

Airplane mode is not a test. Throttled, flapping and high-latency connections each break something different; the emulator’s network profiles cover the first two and a proxy covers the third.

What I would do differently

Start with the conflict rules. They shape the data model, and adding them later means migrating every table.

Related

Contact

Have a useful idea? Let's build it.

Write to me about a project, a job or a question about an article. I reply to every message.

  • Email

    [email — to be provided]
  • Telegram

    [@handle — to be provided]
  • GitHub

    [github.com/… — to be provided]