Monitor the network state to reduce latency
Network Monitor APIs are currently experimental in Apollo Kotlin. If you have feedback on them, please let us know via GitHub issues or in the Kotlin Slack community.
Android and Apple targets provide APIs to monitor the network state of your device:
- ConnectivityManager on Android targets.
- NWPathMonitor on Apple targets.
You can configure your ApolloClient to use these APIs to improve latency of your requests using the NetworkMonitor
API:
// androidMainval networkMonitor = NetworkMonitor(context)// appleMainval networkMonitor = NetworkMonitor()// commonMainval apolloClient = ApolloClient.Builder().serverUrl("https://example.com/graphql").retryOnErrorInterceptor(RetryOnErrorInterceptor(networkMonitor)).build()// once you're done with your `ApolloClient`networkMonitor.close()
failFastIfOffline
When a NetworkMonitor
is configured, you can use failFastIfOffline
to avoid trying out request if the device is offline:
// Opt-in `failFastIfOffline` on all queriesval apolloClient = ApolloClient.Builder().serverUrl("https://example.com/graphql").failFastIfOffline(true).build()val response = apolloClient.query(myQuery).execute()println(response.exception?.message)// "The device is offline"// Opt-out `failFastIfOffline` on a single queryval response = apolloClient.query(myQuery).failFastIfOffline(false).execute()
retryOnError
When a NetworkMonitor
is configured, retryOnError
uses NetworkMonitor.waitForNetwork()
instead of the default exponential backoff algorithm in order to reconnect faster when connectivity is back.
Customizing the retry algorithm
You can customize the retry algorithm further by defining your own interceptor:
val apolloClient = ApolloClient.Builder().retryOnErrorInterceptor(MyRetryOnErrorInterceptor()).build()class MyRetryOnErrorInterceptor : ApolloInterceptor {object RetryException : Exception()override fun <D : Operation.Data> intercept(request: ApolloRequest<D>, chain: ApolloInterceptorChain): Flow<ApolloResponse<D>> {var attempt = 0return chain.proceed(request).onEach {if (request.retryOnError == true && it.exception != null && it.exception is ApolloNetworkException) {throw RetryException} else {attempt = 0}}.retryWhen { cause, _ ->if (cause is RetryException) {attempt++delay(2.0.pow(attempt).seconds)true} else {// Not a RetryException, probably a programming error, pass it throughfalse}}}}