EasyHttp icon indicating copy to clipboard operation
EasyHttp copied to clipboard

[疑惑]:USE_CACHE_FIRST缓存的问题

Open 1399513637 opened this issue 1 year ago • 6 comments

问题描述【必填】

我使用 CacheMode.USE_CACHE_FIRST的时候如果我删除了列表的某项数据然后刷新列表,第一次刷新后使用的还是旧的缓存数据,第二次刷新才会返回新的数据。这个有什么办法解决吗

框架文档是否提及了该问题【必答】

是否已经查阅框架文档但还未能解决的【必答】

issue 列表中是否有人曾提过类似的问题【必答】

是否已经搜索过了 issue 列表但还未能解决的【必答】

1399513637 avatar Jun 30 '24 03:06 1399513637

小伙子,就算没有删除列表项这一说,列表的数据我个人不建议你缓存,因为列表的数据本身就是多变的。

getActivity avatar Jun 30 '24 09:06 getActivity

public final class RequestHandler implements IRequestHandler {

    @Nullable
    @Override
    public Object readCache(@NonNull HttpRequest<?> httpRequest, @NonNull Type type, long cacheTime) {
        String cacheKey = HttpCacheManager.generateCacheKey(httpRequest);
        String cacheValue = HttpCacheManager.readHttpCache(cacheKey);
        if (cacheValue == null || cacheValue.isEmpty() || "{}".equals(cacheValue)) {
            return null;
        }
        EasyLog.printLog(httpRequest, "----- read cache key -----");
        EasyLog.printJson(httpRequest, cacheKey);
        EasyLog.printLog(httpRequest, "----- read cache value -----");
        EasyLog.printJson(httpRequest, cacheValue);
        EasyLog.printLog(httpRequest, "cacheTime = " + cacheTime);
        boolean cacheInvalidate = HttpCacheManager.isCacheInvalidate(cacheKey, cacheTime);
        EasyLog.printLog(httpRequest, "cacheInvalidate = " + cacheInvalidate);
        if (cacheInvalidate) {
            // 表示缓存已经过期了,直接返回 null 给外层,表示缓存不可用
            return null;
        }
        return GsonFactory.getSingletonGson().fromJson(cacheValue, type);
    }

    @Override
    public boolean writeCache(@NonNull HttpRequest<?> httpRequest, @NonNull Response response, @NonNull Object result) {
        String cacheKey = HttpCacheManager.generateCacheKey(httpRequest);
        String cacheValue = GsonFactory.getSingletonGson().toJson(result);
        if (cacheValue == null || cacheValue.isEmpty() || "{}".equals(cacheValue)) {
            return false;
        }
        EasyLog.printLog(httpRequest, "----- write cache key -----");
        EasyLog.printJson(httpRequest, cacheKey);
        EasyLog.printLog(httpRequest, "----- write cache value -----");
        EasyLog.printJson(httpRequest, cacheValue);
        boolean writeHttpCacheResult = HttpCacheManager.writeHttpCache(cacheKey, cacheValue);
        EasyLog.printLog(httpRequest, "writeHttpCacheResult = " + writeHttpCacheResult);
        boolean refreshHttpCacheTimeResult = HttpCacheManager.setHttpCacheTime(cacheKey, System.currentTimeMillis());
        EasyLog.printLog(httpRequest, "refreshHttpCacheTimeResult = " + refreshHttpCacheTimeResult);
        return writeHttpCacheResult && refreshHttpCacheTimeResult;
    }

    @Override
    public boolean deleteCache(@NonNull HttpRequest<?> httpRequest) {
        String cacheKey = HttpCacheManager.generateCacheKey(httpRequest);
        EasyLog.printLog(httpRequest, "----- delete cache key -----");
        EasyLog.printJson(httpRequest, cacheKey);
        boolean deleteHttpCacheResult = HttpCacheManager.deleteHttpCache(cacheKey);
        EasyLog.printLog(httpRequest, "deleteHttpCacheResult = " + deleteHttpCacheResult);
        return deleteHttpCacheResult;
    }

    @Override
    public void clearCache() {
        HttpCacheManager.clearCache();
    }
public final class HttpCacheManager {

    private static final MMKV HTTP_CACHE_CONTENT = MMKV.mmkvWithID("http_cache_content");;

    private static final MMKV HTTP_CACHE_TIME = MMKV.mmkvWithID("http_cache_time");

    /**
     * 生成缓存的 key
     */
    @NonNull
    public static String generateCacheKey(@NonNull HttpRequest<?> httpRequest) {
        IRequestApi requestApi = httpRequest.getRequestApi();
        return "请替换成当前的用户 id" + "\n" + requestApi.getApi() + "\n" + GsonFactory.getSingletonGson().toJson(requestApi);
    }

    /**
     * 读取缓存
     */
    public static String readHttpCache(@NonNull String cacheKey) {
        String cacheValue = HTTP_CACHE_CONTENT.getString(cacheKey, null);
        if (cacheValue == null || cacheValue.isEmpty() || "{}".equals(cacheValue)) {
            return null;
        }
        return cacheValue;
    }

    /**
     * 写入缓存
     */
    public static boolean writeHttpCache(String cacheKey, String cacheValue) {
        return HTTP_CACHE_CONTENT.putString(cacheKey, cacheValue).commit();
    }

    /**
     * 删除缓存
     */
    public static boolean deleteHttpCache(String cacheKey) {
        return HTTP_CACHE_CONTENT.remove(cacheKey).commit();
    }

    /**
     * 清理缓存
     */
    public static void clearCache() {
        HTTP_CACHE_CONTENT.clearMemoryCache();
        HTTP_CACHE_CONTENT.clearAll();

        HTTP_CACHE_TIME.clearMemoryCache();
        HTTP_CACHE_TIME.clearAll();
    }

    /**
     * 获取 Http 写入缓存的时间
     */
    public static long getHttpCacheTime(String cacheKey) {
        return HTTP_CACHE_TIME.getLong(cacheKey, 0);
    }

    /**
     * 设置 Http 写入缓存的时间
     */
    public static boolean setHttpCacheTime(String cacheKey, long cacheTime) {
        return HTTP_CACHE_TIME.putLong(cacheKey, cacheTime).commit();
    }

    /**
     * 判断缓存是否过期
     */
    public static boolean isCacheInvalidate(String cacheKey, long maxCacheTime) {
        if (maxCacheTime == Long.MAX_VALUE) {
            // 表示缓存长期有效,永远不会过期
            return false;
        }
        long httpCacheTime = getHttpCacheTime(cacheKey);
        if (httpCacheTime == 0) {
            // 表示不知道缓存的时间,这里默认当做已经过期了
            return true;
        }
        return httpCacheTime + maxCacheTime < System.currentTimeMillis();
    }
}

getActivity avatar Jun 30 '24 09:06 getActivity

@1399513637 如果你硬是要实现这个需求,可以下载上面的 aar 包进行替换,修改项目中缓存的实现逻辑,另外这一期我修改了框架对外的 api 的参数类型,这块对于你来讲改动有点大,但是仅限参数类型改变了而已,其他实现的没有太大变化,适配完记得多测试一下,有问题记得跟我反馈。

getActivity avatar Jun 30 '24 09:06 getActivity

然后针对你说的删除列表项后对缓存数据刷新的问题,你可以使用 EasyConfig.getInstance().getHandler().deleteCache(HttpRequest<?> httpRequest); 来对原有的缓存内容进行删除。

getActivity avatar Jun 30 '24 09:06 getActivity

好的,我明白了。十分感谢

1399513637 avatar Jun 30 '24 10:06 1399513637