安卓离线缓存实现 | 青训营笔记

162 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第19天。

本文目前功能还未实现完全,后续完成后该行说明会删除!

基于原本仿抖音项目记录新加入的元素,提醒之后的自己

MVVM

分为了common包、discovery包、douyinapi.ui包、main.ui包splash.ui与Application的Java文件。

重点在discovery包

image.png

包下根据MVVM分为Info、model、ui,以下根据目前已有的项目实现离线缓存功能。

依赖

  1. 新增room依赖,在最靠近根部的build.gradle的dependencies下写入
def room_version = "2.4.2"

implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"

之前出过的错:内部与外部的sdk版本不一样,需要注意

代码

1. 在ui包下另分了activity包、adapter包、fragment包(该包因为部分页面存在左右滑动的功能存在,不重点)

image.png

上图FontIconView文件对应实现阿里icon图标实现功能,IamgeViewAttrAdapter实现榜单的拿到url得到对应图片的功能。

adapter包下是各个需要获取数据的部分的适配器。

2. 以DiscoveryVarietyActivity文件为例:

  1. 创建SharedPreferences类型的对象。

SharedPreferences:一个轻量级的存储类,特别适合用于保存软件配置参数。(是用xml文件存放数据,文件存在/data/data/<'package name>/shared_prefs目录下)

private SharedPreferences sharedPreferences;
private Context mContent;
  1. 在initVersionList()方法中异步请求中实现onFailure()方法。

在该方法中写入loadCacheDiscoveryVersion();

@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
    //4.缓存相关
    loadCacheDiscoveryVersions();
}
  • 在loadCacheDiscoveryVersion方法中实现Thread的Runnable的run方法
    • 注意:看起来是直接new一个接口,实际上是匿名内部类!因为接口不能实例化,new Runnable()是一个实现接口Runnable的类的对象,后面的run方法是该类里实现的方法、
  • 在run方法中首先获取db实例、获取操作类、并进行检测
  • mContext在该类被使用,也可以用this代替
private void loadCacheDiscoveryVersions() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            //获取db实例
            AppDatabase db = Room.databaseBuilder(mContext, AppDatabase.class, "xiaoyin").build();
            //获取操作类
            DiscoveryVersionDao discoveryVersionDao = db.discoveryVersionDao();
            //检测
            discoveryVersions = discoveryVersionDao.getItems();
        }
    }).start();

}
  1. 在loadVersionList方法中判断版本jason用optInt获取的error_code是否为0,若为0,进行缓存操作
List<DiscoveryVersion> cacheDiscoveryVersions = new ArrayList<>();

并且在拿出版本信息的for循环当中增加缓存的版本数据

cacheDiscoveryVersions.add(new DiscoveryVersion(startTime, endTime, mVersion));

在跳出for循环后缓存版单版本信息

cacheDiscoveryVersions(cacheDiscoveryVersions);
  1. cacheDiscoveryVersions(cacheDiscoveryVersions);方法如何实现呢?
//缓存榜单版本数据
private void cacheDiscoveryVersions(List<DiscoveryVersion> discoveryVersions) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            //获取db实例
            AppDatabase db = Room.databaseBuilder(mContext, AppDatabase.class, "xiaoyin").build();
            //获取操作类
            DiscoveryVersionDao discoveryVersionDao = db.discoveryVersionDao();
            //检测
            for (int i = 0; i < discoveryVersions.size(); i++) {

                int version = discoveryVersions.get(i).version;
                //判断是否未写入
                if (discoveryVersionDao.getItem(version) == null) {
                    discoveryVersionDao.insertItem(discoveryVersions.get(i));
                }
            }

        }
    }).start();
}
  1. 在初始化initVersionList()中异步请求中实现onFailure方法
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
    //无网络-> 加载缓存
    loadCacheDiscoveries();
}
  1. loadCacheDisvoceries();中如何实现?
@SuppressLint("NotifyDataSetChanged")
//加载缓存数据上去
private void loadCacheDiscoveries() {
    //清空数据
    discoveries.clear();

    new Thread(new Runnable() {
        @Override
        public void run() {
            //获取db实例
            AppDatabase db = Room.databaseBuilder(mContext, AppDatabase.class, "xiaoyin").build();
            //获取操作类
            DiscoveryDao discoveryDao = db.discoveryDao();

            //这里判断一下,如果是初始化,没有version,就记录为0
            int mVersion = 0;
            if (version != null) mVersion = version;

            discoveries = discoveryDao.getItems(mVersion);
            //getActivity.runOnUiThread(new Runnable){
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //判断varietyAdapter是否已经创建了,创建了就再不创建了
                    if (varietyAdapter == null) {
                        //实例化CinemaMovieAdapter
                        varietyAdapter = new VarietyAdapter(discoveries, mContext);
                        //设置Adapter
                        binding.setVarietyAdapter(varietyAdapter);
                        //获取linearLayoutManager
                        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
                        //设置linearLayoutManager
                        binding.setDiscoveryVariety(new DiscoveryVariety(linearLayoutManager, "最后一次更新"));
                    } else {
                        //通知数据变更
                        varietyAdapter.notifyDataSetChanged();
                    }
                }
            });
        }
    }).start();

}
  1. 在解析综艺榜单的loadVarietyList方法中判断传入的error_code是否为0,若为0,则在传入综艺所有数据后进行数据的缓存
cacheDiscoveries(discoveries);
  1. 实现缓存榜单数据
//缓存榜单数据
private void cacheDiscoveries(List<Discovery> discoveries) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            //获取db实例
            AppDatabase db = Room.databaseBuilder(mContext, AppDatabase.class, "xiaoyin").build();
            //获取操作类
            DiscoveryDao discoveryDao = db.discoveryDao();
            //检测
            for (int i = 0; i < discoveries.size(); i++) {

                String id = discoveries.get(i).dataId;
                //判断是否未写入
                //这里判断一下,如果是初始化,没有version,就记录为0
                int mVersion = 0;
                if (version != null) mVersion = version;
                if (discoveryDao.getItem(mVersion, id) == null) {
                    //没有就写入
                    discoveryDao.insertItem(discoveries.get(i));
                }
            }

        }
    }).start();
}

结尾

注意:

  1. Context可以用当前类的this代替,例如在DiscoveryVarietyActivity类则可以用下图510行替代:DiscoveryVarietyActivity.this

image.png

  1. 如果为当前的context的别的属性,可以忽略不写

自此,简短的离线缓存数据的实现告一段落,切记该文未完整,后续回补!