Mobile Design Rounds
CompareAndroidiOS9 min read

Compare the main design choices in the cases

Last reviewed . Drafted with AI assistance, then edited and reviewed by Manuel Lorenzo. Every row links to the section that backs it (how this is checked).

Each case on this site makes a few choices and says why. Every choice has a price. This page puts the same kind of choice side by side. You can see the options, what each one costs, and which case uses it.

I wrote the cases one at a time. This page is the view across all of them. Every row links to the section that backs it. That section says what I checked in official documents and what is my own opinion. The rows are not a full survey. They show what these cases chose, and other teams may choose differently.

Each table has four columns. "Pick it when" names the situation. "What it costs" names the price. "Where" links to the case sections. A choice that is right in one case can be wrong in another. Chat replays the messages that it missed. The live ticker takes a snapshot instead, because a new price replaces the old one.

How the app learns that data changed

In short: Polling asks again and again. A push tells the app to ask. A WebSocket keeps one line open while the app is on screen.

The question is how new data reaches the phone. The phone can ask, the server can tell it, or both can keep a connection open.

No option works in every state of the app, so the cases combine them. The chat app uses a WebSocket on screen and a push hint when the app is closed. The live ticker opens a WebSocket only for the rows the user can see.

ChoicePick it whenWhat it costsWhere
Polling (the app asks again and again)You need the answer for a short time. Booking polls for about a minute after the bank page.It uses battery and data. In the ticker, every answer is already old.Booking app, 2, Chat app, 4.2, Live ticker, 2
Push as a hintThe app is closed. The push only says that something changed, and a sync then fetches the data.A push can be late or lost, so the sync must repair gaps. On iOS a silent push is low priority and not guaranteed.Chat app, 4.2, Chat app, 4.3, Push SDK, 4.2
WebSocketThe app is on screen and the set of items can change, as rows scroll.You rebuild the connection after a drop. On iOS you do this yourself. In the background it is no use, because Doze stops network access.Chat app, 4.2, Live ticker, 2, Live ticker, 4.3
Server-sent events (a one-way stream over HTTP)The set of items is fixed. This is simpler than a WebSocket.The ticker needs subscribe and unsubscribe messages on the same connection, so it did not choose this.Live ticker, 2

How to load a long list

In short: Page numbers break when the list changes. A cursor keeps the place.

Offset paging asks for "page 3". The server counts rows from the top, and the top moves. A new post makes an item repeat. A delete above makes an item go missing. A cursor is a saved place that the server gives to the app.

The short guide Cursor vs offset paging on mobile has the full table. You can watch both fail in the pagination race.

ChoicePick it whenWhat it costsWhere
Offset (page number)The list is short and stable, and the user needs page numbers, as in an admin table.A new item at the top repeats an item. A delete above skips one.Cursor guide, side by side, Pagination library, 2
Cursor (saved place)The list changes while the user reads, as in feeds, chats, notifications and order lists.You cannot jump to page 40. The server must keep a stable order and say what happens to an old cursor.News feed, 2, Chat app, 2, Push SDK, 2
Cursor and a repeat check by IDThe server may re-rank posts between two requests.The app keeps one row for each post ID. I ask which part the backend does, and check anyway.News feed, 2, Cursor guide, when I would choose which

How to make a retry safe

In short: A retry is safe when the server can see that it is a repeat.

Here is the problem. The server did the work, the reply was lost, and the app sends again. An idempotency key is an ID that the app makes once and sends with every retry. The server saves the first result and returns it again.

The guide Idempotency keys on mobile explains who makes the key and how long it lives.

ChoicePick it whenWhat it costsWhere
A random UUID saved with the pending rowThe action costs money or cannot be undone. It is the best choice in the guide.The app must save it before the first send. The server must save the first result.Booking app, 4.1, Chat app, 4.1, Analytics SDK, 2, Travel plans, 2
No key, because the call sets a stateThe action replaces a whole value, such as a like set to true.The server must treat the call as a set. A toggle flips back on a retry.News feed, 4.2, Idempotency guide, when I would choose which
A hash of the request bodyI do not choose it.It fails when two real actions are equal.Idempotency guide, which key is safe
A new key on each try, a timestamp, or a counterI do not choose these.A new key makes each retry a new action. A timestamp can collide. A counter repeats after a reinstall.Idempotency guide, which key is safe

How to run work in the background

In short: Android keeps your job and runs it when its rules are true. iOS only gives you a chance to run.

The two systems make different promises, so one cannot replace the other. The guide WorkManager vs BGTaskScheduler compares them. This table starts from the job, as the guide does.

In every row, the result must not depend on the background run. The app catches up the next time the user opens it. That is why the table lists the job first and the tool second.

JobAndroidiOSWhere
A message or order the user just madeExpedited work, with normal work as a fallbackSend it now. Keep it in your own saved list until the server confirms.Chat app, 4.1, Chat app, 4.3
A large upload the user startedA foreground worker, or a user-initiated data transfer jobA background URLSession, or BGContinuedProcessingTask on iOS 26Photo and file sync, 4.2
A backup the user did not just ask forConstrained WorkManager workA background URLSession, with no promise about when it endsPhoto and file sync, 4.2
Small updates to fresh contentPeriodic workBGAppRefreshTask. Treat it as a bonus.Analytics SDK, 4.1, Background guide, when I would choose which
Heavy work, such as hashingA worker with constraintsBGProcessingTaskBackground guide, when I would choose which
A server that must wake the appA high priority FCM messageA visible push, not a silent pushChat app, 4.2, Push SDK, 4.3

Each tool has a limit. A periodic job on Android cannot repeat faster than every 15 minutes. While Doze is on, WorkManager tasks do not run. On iOS, a refresh task gets up to 30 seconds. A silent push has low priority. The guide cites the official pages for each limit.

How to settle a conflict

In short: Last write wins is simple. It is wrong when order, money or a pending change matters.

A conflict happens when two copies of the data change. The offline-first guide says to use last write wins only when losing the older write is acceptable and you can trust the clocks. You can also use it when the server sets the order. Otherwise, use a number or a version that the server owns.

RulePick it whenWhat it costsWhere
Last write winsLosing the older write is acceptable and the clocks are trusted, or the server sets the order.It fails when a clock is wrong. It also fails when two people change different fields: the older field disappears.Offline-first guide, 4, Travel plans, 2
A server number decides the orderThe data has an order, as chat messages do.The server must give each message a number.Chat app, 2
The local change wins until the server confirmsA pending change must not flip back, as a like must not.The app needs a pending flag. A permanent rejection undoes the change.News feed, 4.2
A version check, then keep bothA file is edited from a base version.The server answers 409, and the user gets a conflicted copy to resolve.Photo and file sync, 6, Offline-first guide, 4
A merge by field, with the server as the judgeDifferent fields should merge, and the same field should show a conflict.Each change carries a base revision. The user sees a conflict with a keep-mine button. A delete leaves a tombstone.Travel plans, 2, Travel plans, 4.2
CRDT (a data type that merges edits by itself)Two people type in one long text.The history grows. Both platforms must follow its rules exactly.Travel plans, 2, Travel plans, 6
Refuse the write while offlineThe action involves money or stock, as a booking does.The user cannot book without a connection.Booking app, 2

How to catch up after a gap

In short: After a gap, ask for changes after a saved place. If the gap is too long, take a fresh snapshot.

A snapshot is a copy of the data at one moment. The travel app takes one when the server says its changes are too old. The ticker takes one after a gap, because a new price replaces the old price. A chat message is different. Each message is a separate fact, so losing one loses information.

MethodPick it whenWhat it costsWhere
Ask for changes after a cursorEach change is a fact that you cannot lose, such as a chat message.The server must keep the changes. After a large gap, the app fetches the latest page and marks the gap.Chat app, 4.2, Chat app, 5
Ask for everything since the last sync timeI do not choose it.It fails when the phone clock is wrong. Deletes never appear in the list.Travel plans, 4.2
Take a snapshot after a gapA new value replaces the old one, as a price does.The app ignores that symbol's ticks until the snapshot arrives.Live ticker, 4.2
Take a snapshot when the server says "too old"The phone was away for weeks.The app keeps its waiting changes and sends them again on top of the new data.Travel plans, 4.2, Travel plans, 5

Where to go next

The other side of this page is the list of failure modes. It shows how an app fails and which sections handle each failure. If you are new, begin at Start here. Did you find a wrong row? Open an issue.

Written by Manuel Lorenzo. The site is drafted with AI assistance and edited and reviewed by him.

Get the free one-page cheat sheet

One page: the five steps, a 45-minute time plan and two checklists. Print it or keep it on your phone.

We email you the cheat sheet after you confirm your address. You can also open it now from the Start here page. You get a short note when a new case is published. Unsubscribe any time. Privacy.