返回介绍

2.2 App 数据缓存设计

发布于 2024-08-17 23:46:12 字数 4451 浏览 0 评论 0 收藏 0

如果以为上一节内容就是网络底层框架的全部,那就错了。那只是网络底层框架的最核心的功能,我们还有很多高级功能没有介绍。在接下来的几节中,我将陆续介绍到这些高级功能。本节先介绍App本地的缓存策略。

2.2.1 数据缓存策略

对于任何一款应用类App,如果访问MobileAPI的速度和牛车一样慢,那么就是失败之作。不要在WiFi下测试速度,那是自欺欺人,要把App放在2G或3G网络环境下进行测试,才能得到大部分用户的真实数据。

访问MobileAPI,主要慢在一来一回的传输速度上,对于服务器的处理速度,不需要担心太多,大多数服务器逻辑原本就是支持网站端的,现在只是在外面包了一层,返回给App而已。

既然时间主要花在了数据传输上,那么我们就要想一些应对的措施。比如说,减少MobileAPI的调用次数。对于一个App页面,它一次性可能需要3部分数据,分别从3个MobileAPI接口获取,那么我们就可以做一个新的MobileAPI接口,将这3部分数据都获取到,然后一次性返回。

减少调用次数只是若干解决方案中的一种,更极端的做法是,App调用一次MobileAPI接口后,在一个时间段内不再调用,仍然使用上次调用接口获取到的数据,这些数据保存在App上,我们称为App缓存,这个时间段我们称为App缓存时间。

App缓存只能针对于MobileAPI中GET类型的接口,对于POST不适用。因为GET是获取数据,而POST是修改数据。

此外,即使是GET类型的接口,对于那些即时性很低的、不怎么改变的数据,比如获取商品的描述,缓存时间可以设置得比较长,比如5~10分钟,对于那些即时性比较高、频繁变动的数据,比如商品价格,缓存时间就会比较短,甚至不能进行缓存。

即使对于同一个需要做App缓存的MobileAPI,参数不同,缓存也是不同的。比如GetWeather.api这个MobileAPI接口,它有一个参数也就是时间date,对于date=2014-9-8和date=2014-9-9,它们就分别对应两个缓存,不能存在一起。

接下来要说的是,App缓存存在哪里,以及以什么方式进行存放。由于缓存数据比较大,所以我们将其存在SD卡上,而不是内存中。这样的话,App缓存策略就仅限于那些有SD卡的手机用户了。

我们可以将xxx.apik1=va&k2=v2这样的URL格式作为key,存放App缓存数据。需要注意的是,我们要对k1、k2这些key进行排序,这样才能唯一,否则对于如下URL:

xxxx.apik1=v1&k2=v2
xxxx.apik2=v2&k1=v1

就会被认为是两个不同的key存放在缓存中,但其实它们是一样的。

对上面的介绍总结如下:

1)对于App而言,它是感受不到取的是缓存数据还是调用MobileAPI。具体工作由网络底层完成。

2)在url.xml中为每一个MobileAPI接口配置缓存时间Expired。对于post,一律设置为0,因为post不需要缓存。

3)在HttpRequest类中的run方法中,改动3个地方:

a)写一个排序算法sortKeys,对URL中的key进行排序。

b)将newUrl作为key,检查缓存中是否有数据,有则直接返回;否则,继续调用MobileAPI接口。

// 如果这个get的API有缓存时间(大于0)
if (urlData.getExpires() > 0) {
  final String content = CacheManager.getInstance()
      .getFileCache(newUrl);
  if (content != null) {
    handler.post(new Runnable() {
      @Override
      public void run() {
        requestCallback.onSuccess(content);
      }
    });
    return;
  }
}

c)MobileAPI接口返回数据后,将数据存入缓存。

final Response responseInJson = JSON.parseObject(
    strResponse, Response.class);
if (responseInJson.hasError()) {
  handleNetworkError(responseInJson.getErrorMessage());
} else {
  // 把成功获取到的数据记录到缓存
  if (urlData.getNetType().equals(REQUEST_GET)
      && urlData.getExpires() > 0) {
    CacheManager.getInstance().putFileCache(newUrl,
        responseInJson.getResult(),
        urlData.getExpires());
  }
  handler.post(new Runnable() {
    @Override
    public void run() {
      requestCallback.onSuccess(responseInJson
          .getResult());
    }
  });
}

4)CacheManager用于操作读写缓存数据,并判断缓存数据是否过期。缓存中存放的实体就是CacheItem。

5)在App项目中,创建YoungHeartApplication这个Application级别的类,在程序启动时,初始化缓存的目录,如果不存在则创建之。

public class YoungHeartApplication extends Application {
  @Override
  public void onCreate() {
    super.onCreate(); 
    CacheManager.getInstance().initCacheDir();
  }
}

记得要在AndroidManifest.xml文件中,指定application的android:name为YoungHeart-Application:

<application
  android:allowBackup="true"
  android:name="com.youngheart.engine.YoungHeartApplication"

对缓存数据,我这里没有做加密,而是直接把明文以字符串类型存放到了SD卡。有这方面特殊需求的App,可以将要缓存的数据转成byte数组再序列化到本地,要用的时候再反过来操作就是了。

2.2.2 强制更新

不光是App端需要记录缓存数据,在MobileAPI的很多接口,其实也需要一样的设计。

如果对于某个接口的数据,MobileAPI缓存了5分钟,App缓存了3分钟,那么最极端的情况是,用户在8分钟内是看不到数据更新的。因此,我们需要在页面上提供一个强制更新的按钮。

我们可以让RemoteService多暴露一个boolean类型的参数,用于判断是否要遵守App端缓存策略,如果是,则在从url.xml中取出UrlData实体后,将其expired强制设置为0,这样就不会执行缓存策略了。

RemoteService的改动如下:

public void invoke(final BaseActivity activity,
    final String apiKey,
    final List<RequestParameter> params,
    final RequestCallback callBack) {
  invoke(activity, apiKey, params, callBack, false);
}
public void invoke(final BaseActivity activity,
    final String apiKey,
    final List<RequestParameter> params,
    final RequestCallback callBack,
    final boolean forceUpdate) {
  final URLData urlData = 
      UrlConfigManager.findURL(activity, apiKey);
  if(forceUpdate) {
    // 如果强制更新,那么就把过期时间强制设置为0
    urlData.setExpires(0); 
  }
  HttpRequest request = 
      activity.getRequestManager().createRequest(
          urlData, params, callBack);
  DefaultThreadPool.getInstance().execute(request);
}

那么在调用的时候,只需要加一个参数就好:

RemoteService.getInstance().invoke(
    this, "getWeatherInfo", params,
    weatherCallback);

数据缓存是一把双刃剑,设置时间长了,数据长期不更新,用户体验就会不好。因此我们需要为那些强迫症类型的用户提供一个强制刷新的按钮,点击按钮后,页面会重新调用MobileAPI加载数据,无论缓存是否到期。

具体这个按钮放在什么位置,就需要产品经理来决策了。我见过很多App都是放在右上角。当然,这是见仁见智的事了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文