Mobile
Lesson 5 of 8About 3 min readSuggest an edit

Networking in mobile apps

A phone’s radio drops out in tunnels, switches between Wi-Fi and mobile data mid-request, and may be on a metered plan. Mobile networking code has to assume that any request can be slow, fail halfway, or never answer.

Timeouts

Every request needs a timeout, and the defaults are not always what you want. URLSession waits up to 60 seconds for data by default, which is far longer than a user will watch a spinner. Set timeouts deliberately for each kind of call.

val client = OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(20, TimeUnit.SECONDS)
    .callTimeout(30, TimeUnit.SECONDS)
    .build()

The call timeout bounds the whole request, including redirects and retries inside the client. A photo upload needs longer timeouts than a screen load, and should run as background work.

Retries

Retry only what is safe to repeat. GET requests are usually safe; a POST that charges a card is not, unless the server supports an idempotency key, as described in the offline-first lesson.

  • Use exponential backoff with jitter: wait roughly 1, 2, 4 seconds, plus a random offset, so thousands of phones don’t retry in step after an outage.
  • Cap the number of attempts.
  • Honour Retry-After on 429 and 503 responses.
  • Don’t retry 4xx errors such as 400 or 401; they will fail the same way again.

Caching and conditional requests

The cheapest request is the one you don’t send. HTTP already has the tools: the server sends Cache-Control and an ETag, and the client repeats the ETag on the next request.

GET /v1/profile
If-None-Match: "a1b2c3"

HTTP/1.1 304 Not Modified

A conditional request that returns 304 has no body, so it saves data and parsing time. URLSession uses URLCache by default; OkHttp caches only if you configure a Cache directory.

Pagination

Never load an unbounded list. Prefer cursor-based pagination, where the server returns an opaque token for the next page, over offset-based paging. Offsets skip or repeat items when rows are inserted while the user scrolls. Load the next page shortly before the user reaches the end of the list, and make sure only one page request is in flight at a time.

Cancel work when screens close

When the user leaves a screen, its requests should stop, rather than wasting data and battery on results nobody will see.

  • On Android, launch requests in viewModelScope; they are cancelled when the ViewModel is cleared.
  • In SwiftUI, work started in the .task modifier is cancelled when the view disappears. With URLSession’s async APIs, cancelling the Swift task cancels the request.

Treat cancellation as normal, not as an error to show the user.

Old app versions live for years

You can deploy a server in minutes, but you cannot update the apps on users’ phones. Some people never update. Every API change must keep working for every app version you still support.

  • Make changes additive: new fields, new endpoints. Don’t rename or remove fields that old apps read.
  • Write clients that ignore unknown fields. Swift’s Codable does by default; with kotlinx.serialisation set ignoreUnknownKeys = true.
  • Handle unknown enum values with a fallback case instead of failing to decode the whole response.
  • When a breaking change is unavoidable, version the API (for example /v2/) and keep the old version running until usage is negligible.
  • Send the app version in a header, so the server can see who is calling and adapt.

Smaller payloads

Mobile data costs users money and time. Compress responses with gzip or Brotli; OkHttp requests gzip automatically. Return only the fields a screen needs, and avoid chatty screens that make ten requests where one would do.

Checklist

  • Explicit timeouts, chosen per type of request.
  • Retries only for idempotent requests, with backoff, jitter and a cap.
  • ETags or Last-Modified on resources that change rarely.
  • Cursor pagination for every list that can grow.
  • Requests tied to the lifetime of the screen that started them.
  • Tolerant decoding, additive API changes and an app version header.

Next: Push notifications and background work

How APNs and FCM deliver pushes, token handling, permission prompts and running work in the background.