How does the retrofit framework implement a request to return cached data first and then return network data?

now there is a requirement that, regardless of whether the network is available or not, load the local cache first, and if the network is available and request network data, the latest data will be displayed if it is returned successfully. This improves the user experience so that the page of the poor network is not blank. However, the framework of retrofit does not seem to be implemented. It implements custom caching by adding interceptors. One request returns either cached data or network data, but not both

.
/**
     * 
     */
    private static final Interceptor cacheControlInterceptor = new Interceptor() {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!NetWorkUtils.isNetworkAvailable(GApp.getInstance())) {
                request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
                Log.i("ww", "no network");
            }
            Response response = chain.proceed(request);

            if (NetWorkUtils.isNetworkAvailable(GApp.getInstance())) {
                //   String cacheControl = request.cacheControl().toString();
                return response.newBuilder()
                        .header("Cache-Control", CACHE_CONTROL_NETWORK)
                        .removeHeader("Pragma")
                        .build();
            } else {
                return response.newBuilder()
                        .header("Cache-Control", "public, " + CACHE_CONTROL_CACHE)
                        .removeHeader("Pragma")
                        .build();
            }
        }
    };
Mar.16,2021

write local cache by yourself


if you use Repository mode, you can achieve
first refer to Android-MVP to learn about Repository mode

Retrofit belongs to the network request framework, so RemoteDataSource, should not handle cache-related transactions in Repository mode. Caching is done in the Repository class, which is persisted when fetching data remotely, and then can be fetched locally when requested again.

this is an example of myself before.
first requests data from the local DataSource. A remote request is initiated in the callback after a successful request, and a remote request is also initiated in the callback where the request fails. In this way, the callback will be executed twice, which can achieve the effect you mentioned.

@Override
public void grabCatalog(@NonNull final String novelId, final GetDataCallback<Catalog> callback,
        final LoadingCallback loadingCallback) {
    mCatalogLocalDataSource.getCatalog(novelId, new GetDataCallback<Catalog>() {
        @Override
        public void onDataLoaded(@NonNull Catalog catalog) {
            callback.onDataLoaded(catalog);
            mCatalogRemoteDataSource.getCatalog(novelId, new GetDataCallback<Catalog>() {
                @Override
                public void onDataLoaded(@NonNull Catalog catalog) {
                    catalog.setNovelId(novelId);
                    callback.onDataLoaded(catalog);
                    mCatalogLocalDataSource.saveCatalog(catalog);
                    refreshCache(catalog);
                }

                @Override
                public void onDataNotAvailable(Error error) {
                    // do nothing
                }
            });
        }

        @Override
        public void onDataNotAvailable(Error error) {
            loadingCallback.onShowLoading();
            mCatalogRemoteDataSource.getCatalog(novelId, new GetDataCallback<Catalog>() {
                @Override
                public void onDataLoaded(@NonNull Catalog catalog) {
                    catalog.setNovelId(novelId);
                    callback.onDataLoaded(catalog);
                    mCatalogLocalDataSource.saveCatalog(catalog);
                    refreshCache(catalog);
                    loadingCallback.onHideLoading();
                }

                @Override
                public void onDataNotAvailable(Error error) {
                    // loadingCallback.onHideLoading();
                    callback.onDataNotAvailable(error);
                }
            });
        }
    });
}
Menu