Advanced Android Network Programming and Optimization (3): Advanced Retrofit Usage
This is part 3 of the three-part “Advanced Android Network Programming and Optimization” series. In the previous article, we covered “OkHttp internals: the networking Swiss army knife.”
3. Advanced Retrofit usage: defining APIs cleanly
Retrofit provides a declarative, type-safe API layer on top of OkHttp.
1. Core advantage
Retrofit uses annotations to define HTTP requests, including URL, method, headers, and body, abstracts HTTP APIs as Java/Kotlin interfaces, and automatically handles request construction and response parsing.
2. Advanced features and extensions
Custom CallAdapter (CallAdapter.Factory)
- Role: controls the return type and execution model of Retrofit interface methods. The default supports
Call<T>. Official and community adapters support RxJava types such asSingle<T>andObservable<T>, and coroutines such assuspend funandDeferred<T>. - Applications:
- Unified result wrapping: wrap all network responses, successful or failed, into a custom
Result<T>orApiResponse<T>type that contains data or error information such as business error code, HTTP error, or network exception. This simplifies upper-layer logic. - Specific error handling: intercept particular HTTP status codes or exception types in the adapter for global handling or conversion.
- Integration with other async frameworks: adapt beyond coroutines and RxJava when needed.
- Unified result wrapping: wrap all network responses, successful or failed, into a custom
Custom Converter (Converter.Factory)
- Role: controls request-body serialization and response-body deserialization. Defaults support JSON libraries such as Gson, Moshi, and Jackson, plus Protobuf and Scalars for strings and primitive types.
- Applications:
- Support non-standard formats such as XML or custom binary formats.
- Clean, transform, or validate data during serialization/deserialization.
- Implement partial parsing, such as extracting one specific field from a JSON response.
- Support compatibility across multiple data formats, such as JSON and Protobuf.
Dynamic URL with @Url: when the request URL is not derived from Base URL plus Path and must be fully dynamic, use @Url String url as a method parameter. Retrofit treats it as the complete request URL.
Dynamic headers with @Header and @HeaderMap: add request headers from method parameters.
Multipart requests with @Multipart, @Part, and @PartMap: used for file upload and multipart/form-data requests, together with RequestBody and MultipartBody.Part.
Robust error handling: combine Response<T>, errorBody() parsing, and custom CallAdapter logic to distinguish network errors, HTTP errors, and business errors.
4. Beyond REST: gRPC and WebSocket
For certain scenarios, REST over HTTP is not the best fit.
1. gRPC
Core: gRPC uses Protocol Buffers for interface definition and data serialization, and usually runs over HTTP/2.
Advantages:
- High performance: Protobuf is binary, fast to serialize and deserialize, and compact. HTTP/2 provides multiplexing and header compression.
- Strongly typed contract: Protobuf defines strict services and interfaces. Cross-language code generation preserves type safety.
- Streaming support: four modes are supported: Unary, Server streaming, Client streaming, and Bidirectional streaming.
- Language independence: well suited for multi-language microservice environments.
Disadvantages:
- Poor readability: Protobuf is binary.
- Ecosystem and tooling: compared with REST/JSON, it requires Protobuf compilation and gRPC library integration. Direct browser support is limited and requires gRPC-Web.
- Debugging and proxying: generic proxy tools are less convenient than with HTTP/JSON.
Android usage:
- Use grpc-java or grpc-kotlin.
- Manage
ManagedChannel, which represents the connection to the server. - Coroutine integration is good through grpc-kotlin.
- Use cases: high-performance internal APIs, streaming communication such as real-time data push or large file chunk transfer, and service-to-service calls in microservice architectures.
2. WebSocket
Core: WebSocket is a full-duplex persistent communication channel over TCP after an initial HTTP handshake. Server and client can send messages to each other at any time.
Advantages:
- Very low latency: after the connection is established, data transfer avoids per-request HTTP request/response overhead. It is ideal for real-time scenarios.
- Real-time bidirectional communication: the server can proactively push messages to the client.
Disadvantages:
- Server pressure: servers must maintain many persistent connections, which increases architectural and resource requirements.
- Not request/response oriented: not suitable for traditional RESTful API interaction.
- State management: the connection is stateful, so setup, disconnect, and reconnect logic must be handled.
- Battery consumption: keeping long-lived mobile connections, especially in the background, can significantly increase power use if done poorly. Heartbeats and lifecycle management must be carefully designed.
- Firewalls and proxies: WebSocket may be blocked by intermediate network devices more easily than HTTPS.
Android usage:
- OkHttp supports WebSocket with
client.newWebSocket(request, listener). - Implement
WebSocketListenerand handleonOpen,onMessage,onClosing,onClosed, andonFailure. - Use cases: instant messaging, real-time market data, online games, collaborative editing, and other low-latency bidirectional scenarios.
- Considerations: design robust connection management with heartbeat, reconnect, and exponential backoff; choose a message protocol such as JSON or Protobuf; define background survival strategy through Foreground Service or WorkManager checks; and evaluate battery impact.
5. Network optimization strategies
Network performance must be optimized across multiple dimensions.
1. Connection optimization
- Connection pooling: the core optimization. Share the OkHttpClient instance, configure ConnectionPool reasonably with
maxIdleConnectionsandkeepAliveDuration, and monitor hit rate through EventListener. - Enable HTTP/2 and QUIC/HTTP/3: enable them on both client and server. Prefer QUIC when available for the best mobile performance.
- TLS optimization
- TLS 1.3: faster and safer handshake. Ensure the server supports it.
- 0-RTT/1-RTT: when supported and safe for the business context, reduce handshake latency. Consider replay attack risk.
- Certificate chain optimization: the server should provide a complete and short certificate chain.
- OCSP Stapling: configure server-side stapling to reduce client-side online certificate status validation latency.
- DNS optimization
- HTTPDNS and DoH: use HTTPDNS services or implement DNS-over-HTTPS with custom OkHttp DNS to bypass carrier local DNS hijacking and pollution, and potentially achieve faster resolution and better routing.
- Smart caching: implement longer and smarter DNS caching than the system default when appropriate.
- Prefetching: pre-resolve critical domains during app startup or idle time.
EventListener.dnsStartanddnsEndcan be used for implementation and monitoring. - Concurrent resolution: resolve multiple domains concurrently when needed.
- Pre-connection
- Timing: before a user is likely to perform a network operation, such as app startup or entering a specific screen, establish TCP and TLS connections to target servers.
- Implementation: send lightweight requests such as HEAD or OPTIONS to trigger connection setup, or use lower-level OkHttp APIs. Prediction must be accurate.
- Effect: the actual request can reuse an already established connection and avoid handshake latency.
- Cost: may create unused connections and consume resources, so use an intelligent strategy.
2. Request and data optimization
- Request priority: distinguish priorities for concurrent requests. User-triggered critical actions such as payment should outrank background sync. OkHttp Dispatcher does not directly support priority queues, but custom ExecutorService or upper-layer dispatch logic can implement it.
- Request coalescing and batching: when the backend supports it, such as GraphQL or a custom batch endpoint, merge multiple related small requests into one network request to reduce request count and round trips.
- Caching and conditional requests
- HTTP cache: extremely important. Use HTTP cache mechanisms such as Cache-Control, ETag, and Last-Modified, and configure OkHttp Cache correctly. For cacheable resources such as images, configuration, and infrequently changing API data, this can greatly reduce network transfer and speed up loading. Server response headers must be correct.
- Application-level cache: for data that cannot rely on HTTP cache or needs a longer validity period, use memory cache such as LruCache and disk cache such as DiskLruCache, Room, or MMKV.
- Data compression
- Transport layer: enable Gzip or Brotli compression, requiring client Accept-Encoding and server support. OkHttp handles Gzip by default.
- Data format: choose more compact formats. Protobuf is usually smaller and faster to parse than JSON.
- Request body compression: for large POST or PUT bodies such as JSON, consider compressing the body.
- Reduce chattiness: design APIs so clients do not need many consecutive calls to assemble complete data. Return all necessary information in one request when reasonable.
- Delta updates: for lists or large objects, transmit only changed parts where possible instead of full data every time. This requires protocol support from both frontend and backend.
3. Weak and mobile network optimization
- Dynamic timeouts: use ConnectivityManager network type or a network-quality estimator to adjust OkHttp connect/read/write timeouts. Extend timeouts on weak networks and shorten them on strong networks to fail fast.
- Request deduplication: when users can trigger repeated actions quickly, such as tapping refresh, deduplicate identical or logically equivalent requests within a short time window.
- Smart retries
- Classify errors: retry only transient network jitter, timeouts, and temporary server errors such as 5xx. Client errors such as 4xx usually should not be retried.
- Exponential backoff: retry intervals grow exponentially, such as 1s, 2s, 4s, and 8s, to avoid worsening congestion. Add jitter.
- Limit attempts: set a maximum retry count.
- Adaptive payload and quality
- Images: request different resolutions or quality levels based on network conditions. WebP is usually better than JPEG or PNG.
- Video: adjust bitrate based on speed, similar to DASH or HLS.
- API data: request compact data or use pagination when the backend supports it.
- Offline support
- Data cache: cache data aggressively for offline viewing.
- Request queue: store delayable user actions such as posting or liking in a local queue, for example Room plus WorkManager, and send them automatically when the network recovers.
6. Performance monitoring and diagnosis
Without monitoring, optimization is guesswork.
- OkHttp EventListener: the core monitoring tool. Collect timings across DNS, TCP, TLS, request transfer, and response transfer, upload them to an APM system, and compute P50/P90/P99 latency, error rate, connection reuse rate, and other key metrics.
- Android Studio Network Inspector: valuable during development and debugging. It shows request details, waterfall timing, and response content.
- Proxy tools such as Charles Proxy, Proxyman, Fiddler, and Wireshark
- Functions: intercept, inspect, modify, and replay HTTP/HTTPS traffic; analyze request details, protocol behavior, and encrypted content after certificate setup; simulate slow networks and different responses.
- Uses: deep debugging of network issues, API behavior analysis, and security testing.
- Server logs and monitoring: combine client-side metrics with server processing time and error logs to identify root causes.
- Real User Monitoring (RUM)
- Tools: Firebase Performance Monitoring, Sentry, Bugsnag, custom APM systems, and services such as Alibaba Cloud ARMS.
- Value: collect real user network performance data across real networks and devices, including request duration, success rate, and data usage. This reveals issues that lab environments miss, evaluates optimization results, and supports analysis by version, region, and network type.
7. Conclusion: network optimization is continuous refinement
Android network performance is central to user experience, especially in complex and changing mobile networks. Advanced network programming and optimization require both depth and breadth:
- Understand the foundation: know the evolution of HTTP protocols, including HTTP/2, QUIC, and HTTP/3, and the opportunities and challenges they bring.
- Master the tools: understand OkHttp internals and advanced configuration, and use higher-level abstractions such as Retrofit effectively.
- Adopt new technologies: understand gRPC, WebSocket, and other modern communication protocols, and introduce them when appropriate.
- Use a complete strategy: apply connection reuse, request management, compression, caching, and weak-network adaptation systematically.
- Be data-driven: use EventListener, RUM, and other monitoring systems to measure performance, find bottlenecks, and validate improvements.
Network optimization is not a one-time task. It must iterate with business growth, technology evolution, and user feedback. Deep networking knowledge and practical experience are what let teams build apps that are fast, reliable, resource-efficient, and pleasant to use across real-world network conditions.
Advanced Android Network Programming and Optimization series
- Networking as the app’s lifeline
- OkHttp internals: the networking Swiss army knife
- Advanced Retrofit usage: defining APIs cleanly (this article)