Uploads, downloads, progress, cancellation, and streaming
Stream instead of buffering
Never call bytes()/load entire multi-GB body into memory. Stream source to sink with bounded buffer, close with use, and move blocking I/O to appropriate dispatcher/API.
response.body.byteStream().use { input ->
temp.outputStream().use { output -> input.copyTo(output, bufferSize = 64 * 1024) }
}
Verify HTTP success before consuming. Write temporary file, validate length/checksum/content, then atomically rename. On cancellation/failure, remove or retain partial according to resume policy.
Progress
Wrap RequestBody/ResponseBody counting bytes and emit throttled progress. Emitting every 8KB can overwhelm Main/recompose. Total may be unknown for chunked/compressed transfer; represent indeterminate progress.
Progress “100% uploaded” means request bytes sent, not server processed. Wait for accepted response/status.
Multipart
Validate content URI through ContentResolver; do not assume path, filename, MIME, length, or continued permission. Stream with size limits. Sanitize server-visible filename; never trust extension as content type.
Resumable transfers
Large reliable upload usually needs server protocol:
- create upload session/idempotency identity
- split into numbered/checksummed chunks
- persist acknowledged offsets/chunks
- retry chunks safely
- finalize atomically
- query status after ambiguity
HTTP Range download must verify ETag/version so bytes from changed resource are not appended.
Cancellation ownership
Screen coroutine cancellation suits disposable preview. User-requested durable upload belongs in repository/WorkManager and continues beyond screen; UI observes persistent status. Cancel action updates durable state and server session where supported.
Security/resource limits
- maximum bytes/time/decompressed size
- archive bomb/path traversal prevention
- checksum/authenticated source where required
- disk-space preflight and low-storage recovery
- no secret URLs/tokens in filenames/logs
- TLS and authorization on every resume request
Replaying a multipart POST may duplicate server state. Use a documented resumable/idempotent protocol rather than assuming network library retry is safe.
Exercises
- Design 2GB resumable upload across process death.
- Throttle progress without losing final state.
- Securely stream a user-selected content URI.