android两种方式实现离线缓存

android实现离线缓存

在这个无法缺失互联网的世界里[android离线缓存][6]将解决在没有互联网的环境中APP的使用,目前使用这项技术的有网易新闻,神马新闻,主要的优点是:

  • 实现离线浏览,在离线状态下,浏览新闻(也可以用H5实现)
  • 减轻服务器压力,降低服务器的并发性操作
  • 提高客户端的响应速度

其实现的方式主要有:

  • 保存到本地文件存储
  • 保存到SQLite数据库存储

保存到本地文件存储

将网络数据保存到本地:首先需要写一个将网络数据保存到本地的方法。

public static boolean saveObject(Serializable ser, String file) {
    FileOutputStream fos = null;
    ObjectOutputStream oos = null;
    try {
        fos = AppContext.getInstance().openFileOutput(file, AppContext.getInstance().MODE_PRIVATE);
        oos = new ObjectOutputStream(fos);
        oos.writeObject(ser);
        oos.flush();
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    } finally {
        try {
            oos.close();
        } catch (Exception e) {
        }
        try {
            fos.close();
        } catch (Exception e) {
        }
    }
}

openFileOutput可以直接获得一个和应用关联的文件路径(在/data/data//files下面),然后使用java io中的ObjectOutputStream将序列化的对象写入(writeObject)到得到的文件中,你可以看到上面的实现过程有两个关键方法:openFileOutput、writeObject以及调用它们的两个关键对象Context和ObjectOutputStream。
这是将一个序列化的对象保存在本地,跟我们的离线缓存保存网络数据有什么关系呢?

有关系,因为网上获取的数据大多可以转换成String类型的字符串,现在服务端返回的数据一般是json格式的字符串。

用上面的saveObject方法我们可以将数据保存在本地,为了能够取出这个文件我们必须想好如何为这个保存的文件命名,如果是单纯的一篇文章的数据,我们可以直接将文件名命名为这篇文章的id,因为id是唯一的,为了尽可能的不和其他数据发生冲突,你还可以在这个id之前加一个前缀,比如这篇文章是java栏目下的我们可以这样 arc_java_id。如果是文章列表我们可以这样命名:文章类别_分页页码,总之命名的原则是能和其他离线数据区别,有唯一性。为什么不用url作为文件名呢?url肯定是唯一的,但是url不一定符合文件的命名规范。


读取本地的缓存数据:
读取缓存的时候根据文件名读取缓存,下面的readObject方法实现了根据文件名读取缓存数据。

/**
 * 读取对象
 *
 * @param file
 * @return
 * @throws IOException
 */
public static Serializable readObject(String file) {
    FileInputStream fis = null;
    ObjectInputStream ois = null;
    try {
        fis = AppContext.getInstance().openFileInput(file);
        ois = new ObjectInputStream(fis);
        return (Serializable) ois.readObject();
    } catch (FileNotFoundException e) {
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            ois.close();
        } catch (Exception e) {
        }
        try {
            fis.close();
        } catch (Exception e) {
        }
    }
    return null;
}
  • 下面的代码演示了如何用上面的知识存储和读取网络数据
String key = codelist_ +  mCategory.getValue()  + _ + + page ;
String result = ;
//cache
if (HttpUtil.isNetworkConnected()) {
        result = HttpUtil.http_get(AppContext.getInstance(), url );
        HttpUtil.saveObject(result, key);
        result = (String) HttpUtil.readObject(key);
} else {
    result = (String) HttpUtil.readObject(key);
    if (result == null)
        result = erro;
}

当网络畅通时, 从服务器获取数据(HttpUtil.http_get(AppContext.getInstance(), url )),同时将数据保存到本地(HttpUtil.saveObject),而当网络不可用时,直接从本地读取缓存的数据,不跟服务器发生交互。

拓展:

有时候我们还有这样的需求,当用户在指定间隔时间内读取同一数据源时,从本地获取,超过这个时间间隔从网络获取,这样做的目的是节省用户的流量,同时也避免了每次从网络获取数据造成的界面延迟。
下面实现了如何根据时间间隔判断是否需要刷新服务器数据,true表示不需要,false表示需要

public static boolean isCacheDataFailure(String cachefile) {
    boolean failure = false;
    File data = AppContext.getInstance().getFileStreamPath(cachefile);
    if (data.exists()
            && (System.currentTimeMillis() - data.lastModified()) > CACHE_TIME)
        failure = true;
    else if (!data.exists())
        failure = true;
    return failure;
}

将当前时间和文件的修改时间做比较 ,CACHE_TIME是一个固定值(毫秒),你可以替换成任意int类型。

完整应用代码:
String key = codelist_ +  mCategory.getValue()  + _ + + page ;
String result = ;
//cache
if (HttpUtil.isNetworkConnected() && HttpUtil.isCacheDataFailure(key)) {
        result = HttpUtil.http_get(AppContext.getInstance(), url );
        HttpUtil.saveObject(result, key);
        result = (String) HttpUtil.readObject(key);
} else {
    result = (String) HttpUtil.readObject(key);
    if (result == null)
        result = erro;
}

完善功能:
上面的步骤对于一般应用来说已经够用了,但是在要求比较高的情况下,我们还得考虑随着时间的流逝,缓存数据会越来越多,因此我们需要增加删除过期缓存的功能,原理就是设置一个阀值,在保存缓存的时候,判断当前缓存的总量是否大于阀值,如果是则删除时间较早的缓存,前提是你保存了时间属性。

这个实现起来有点复杂,可以考虑更简单的方案,定期检查(或者用户每打开一次程序)缓存总量,当大于阀值,提示用户主动删除。


保存到SQlite数据库存储

实现方法:这种方法是在下载完数据文件后,把文件的相关信息如url,路径,下载时间,过期时间等存放到数据库,当然我个人建议把url作为唯一的标识。下次下载的时候根据url先从数据库中查询,如果查询到当前时间并未过期,就根据路径读取本地文件,从而实现缓存的效果。

优点:这种方法可以灵活存放文件的属性,进而提供了很大的扩展性,可以为其它的功能提供一定的支持。

缺点:从操作上需要创建数据库,每次查询数据库,如果过期还需要更新数据库,清理缓存的时候还需要删除数据库数据,稍显麻烦,而数据库操作不当又容易出现一系列的性能,ANR问题,指针错误问题,实现的时候要谨慎,具体实现的话,但也只是增加一个工具类或方法的事情。同时,缓存的数据库是存放在/data/data//databases/目录下,是占用内存空间的,如果缓存累计,容易浪费内存,需要及时清理缓存。

有利有弊,开发者根据用户自己的操作习惯和使用情境选择对应的方式。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端离线缓存可以通过HTML5的离线存储(Application Cache)来实现。该机制是基于一个manifest文件的缓存机制,通过在manifest文件中定义需要缓存的文件,浏览器会将这些文件保存在本地。当网络处于离线状态时,浏览器会使用离线存储的数据进行页面展示。这种机制主要适用于内容变动少、相对固定的场景下。 另外,还可以借助Service Worker和cacheStorage缓存实现离线缓存。Service Worker是一种在浏览器后台运行的脚本,可以拦截网络请求并缓存响应,从而实现离线缓存。cacheStorage是浏览器提供的API,用于管理缓存存储空间。 在实际开发中,可以使用Workbox webpack Plugins等工具来简化离线缓存的配置和管理。这些工具可以帮助我们生成Service Worker脚本,并提供一些方便的API来管理缓存离线状态。 总结起来,前端离线缓存可以通过HTML5的离线存储、Service Worker和cacheStorage缓存等技术来实现。这些技术可以提供离线访问和更好的用户体验。 #### 引用[.reference_title] - *1* *2* *3* [【万字长文】前端离线化/长缓存方案](https://blog.csdn.net/sinat_36521655/article/details/120051358)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值