Created
October 14, 2021 21:23
-
-
Save davidalbers/6c10ac744b4ef49560e646475ecd7757 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Signal the apollo client to fetch the data from both the network and the cache. If cached data is not present, only | |
* network data will be returned. If cached data is available, but network experiences an error, only cached data is | |
* returned. If cache data is not available, and network data is not available, the error | |
* of the network request will be propagated. If both network and cache are available, both will be returned. Cache data | |
* is guaranteed to be returned first. | |
* | |
* Modified from Apollo's CacheAndNetworkFetcher | |
* https://github.com/apollographql/apollo-android/blob/f72c3afd17655591aca90a6a118dbb7be9c50920/apollo-runtime/src/main/java/com/apollographql/apollo/internal/fetcher/CacheAndNetworkFetcher.java#L1 | |
*/ | |
class CacheWithOptionalNetworkFetcher : ResponseFetcher { | |
override fun provideInterceptor(apolloLogger: ApolloLogger): ApolloInterceptor { | |
return CacheAndNetworkInterceptor() | |
} | |
private class CacheAndNetworkInterceptor : ApolloInterceptor { | |
private var cacheResponse = Optional.absent<InterceptorResponse>() | |
private var networkResponse = Optional.absent<InterceptorResponse>() | |
private var cacheException = Optional.absent<ApolloException>() | |
private var networkException = Optional.absent<ApolloException>() | |
private var dispatchedCacheResult = false | |
private var originalCallback: ApolloInterceptor.CallBack? = null | |
@Volatile | |
private var disposed = false | |
override fun interceptAsync( | |
request: InterceptorRequest, chain: ApolloInterceptorChain, | |
dispatcher: Executor, callBack: ApolloInterceptor.CallBack | |
) { | |
if (disposed) return | |
originalCallback = callBack | |
val cacheRequest = request.toBuilder().fetchFromCache(true).build() | |
chain.proceedAsync(cacheRequest, dispatcher, object : ApolloInterceptor.CallBack { | |
override fun onResponse(response: InterceptorResponse) { | |
handleCacheResponse(response) | |
} | |
override fun onFailure(e: ApolloException) { | |
handleCacheError(e) | |
} | |
override fun onCompleted() {} | |
override fun onFetch(sourceType: FetchSourceType) { | |
callBack.onFetch(sourceType) | |
} | |
}) | |
val networkRequest = request.toBuilder().fetchFromCache(false).build() | |
chain.proceedAsync(networkRequest, dispatcher, object : ApolloInterceptor.CallBack { | |
override fun onResponse(response: InterceptorResponse) { | |
handleNetworkResponse(response) | |
} | |
override fun onFailure(e: ApolloException) { | |
handleNetworkError(e) | |
} | |
override fun onCompleted() {} | |
override fun onFetch(sourceType: FetchSourceType) { | |
callBack.onFetch(sourceType) | |
} | |
}) | |
} | |
override fun dispose() { | |
disposed = true | |
} | |
@Synchronized | |
fun handleNetworkResponse(response: InterceptorResponse) { | |
networkResponse = Optional.of(response) | |
dispatch() | |
} | |
@Synchronized | |
fun handleNetworkError(exception: ApolloException) { | |
networkException = Optional.of(exception) | |
dispatch() | |
} | |
@Synchronized | |
fun handleCacheResponse(response: InterceptorResponse) { | |
cacheResponse = Optional.of(response) | |
dispatch() | |
} | |
@Synchronized | |
fun handleCacheError(exception: ApolloException) { | |
cacheException = Optional.of(exception) | |
dispatch() | |
} | |
@Synchronized | |
private fun dispatch() { | |
if (disposed) { | |
return | |
} | |
if (!dispatchedCacheResult) { | |
if (cacheResponse.isPresent) { | |
val cached = cacheResponse.get() | |
originalCallback!!.onResponse(cached) | |
dispatchedCacheResult = true | |
} else if (cacheException.isPresent) { | |
dispatchedCacheResult = true | |
} | |
} | |
// Only send the network result after the cache result has been dispatched | |
if (dispatchedCacheResult) { | |
if (networkResponse.isPresent) { | |
originalCallback!!.onResponse(networkResponse.get()) | |
originalCallback!!.onCompleted() | |
} | |
} | |
if (cacheException.isPresent && networkException.isPresent) { | |
// only send network exception if both network and cache have failed | |
originalCallback!!.onFailure(networkException.get()) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment