数据缓存

一、Greendao简介

 Greendao是一款用于数据库创建与管理的框架,由于原生SQLite语言比较复杂繁琐,使得不少程序员不得不去学习SQLite原生语言,但是学习成本高,效率低下,所以不少公司致力于开发一款简单的数据库管理框架,较为著名的就有Greendao和ORMLite,但是就数据分析来看,Greendao的效率是高于ORMLite及其他框架的,是目前该行业的领先者。也因为Greendao的使用方法简便,且效率高使得其成为目前使用最为广泛的数据库管理框架,这也是广大程序员的福音。

二、Greendao的使用方法

1.添加依赖

在bulid.gradle文件下的dependencies下添加所需依赖

[java] view plain copy
compile ‘org.greenrobot:greendao:3.2.2’ // add library
compile ‘org.greenrobot:greendao-generator:3.2.2’

2.在bulid.gradle下进行配置

[java] view plain copy
apply plugin: ‘org.greenrobot.greendao’
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath ‘org.greenrobot:greendao-gradle-plugin:3.2.2’
}
}

3.对greendao的generator生成文件进行配置

[java] view plain copy
greendao {
schemaVersion 1 //版本
daoPackage ‘生成文件包名’ // 一般为app包名+生成文件的文件夹名
targetGenDir ‘src/main/java’ //生成文件路径
}

4.创建实体类,生成dao文件

[java] view plain copy
@Entity
public class dayStep {
@Id
private long id;
private String date;
private int step;
private Long sportId;
@ToOne(joinProperty = ” sportId”)
private SportInfo sportInfo;//关系表
}
注意:编写完实体类以后在实体类界面下按下Ctrl+F9(Make project),程序会自动编译生成dao文件,生成的文件一共有三个。

Greendao生成文件

5.使用Greendao

(1)创建一个application类,在application中完成DaoSession的初始化,避免以后重复初始化,便于使用。

[java] view plain copy
public class MyApplication extends Application {
private DaoMaster.DevOpenHelper mHelper;
private SQLiteDatabase db;
private DaoMaster mDaoMaster;
private DaoSession mDaoSession;
//静态单例
public static MyApplication instances;
@Override
public void onCreate() {
super.onCreate();
instances = this;
setDatabase();
}
public static MyApplication getInstances(){
return instances;
}

/** 
 * 设置greenDao 
 */  
private void setDatabase() {  
    // 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。  
    // 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。  
    // 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。  
    // 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。  
    mHelper = new DaoMaster.DevOpenHelper(this, "sport-db", null);  
    db = mHelper.getWritableDatabase();  
    // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。  
    mDaoMaster = new DaoMaster(db);  
    mDaoSession = mDaoMaster.newSession();  
}  
public DaoSession getDaoSession() {  
    return mDaoSession;  
}  
public SQLiteDatabase getDb() {  
    return db;  
}  

}

(2)Greendao操作数据库文件(增,删,改,查)

[java] view plain copy
/**
* 增
*/
public void insert()
{
String date = new Date().toString();
mDayStep = new dayStep(null,date,0);//第一个是id值,因为是自增长所以不用传入
dao.insert(mDayStep);
}

/** 
 * 查 
 */  
public void Search()  
{  
    //方法一  
    List<dayStep> mDayStep = dao.loadAll();  
    //方法二  
    //List<dayStep> mDayStep = dao.queryBuilder().list();  
    //方法三 惰性加载  
    //List<dayStep> mDayStep = dao.queryBuilder().listLazy();  
    for (int i = 0; i < mDayStep.size(); i++) {  
        String date = "";  
        date = mDayStep.get(i).getDate();  
        Log.d("cc", "id:  "+i+"date:  "+date);  
    }  


}  


/** 
 * 删 
 * @param i 删除数据的id 
 */  
public void delete(long i)  
{  
    dao.deleteByKey(i);  
    //当然Greendao还提供了其他的删除方法,只是传值不同而已  
}  


/** 
 *改 
 * @param i 
 * @param date 
 */  
public void correct(long i,String date)  
{  
    mDayStep =  new dayStep((long) i,date,0);  
    dao.update(mDayStep);  
}  

/**
*修改或者替换(有的话就修改,没有则替换)
*/
public void insertOrReplace(long i,String date)
{
mDayStep = new dayStep((long) i,date,0);
dao.insertOrReplace(mDayStep);
}

/**
*查找符合某一字段的所有元素
*/
public void searchEveryWhere(String str)
{
List mList = dao.queryBuilder()
.where(dao.date.eq(str)).build().listLazy();
}

三、多表关联
一对一与一对多概念几乎类似,我们在这里就只做一对多的讲解(我们实现一个用户有多张运动表,运动表就是用户表的儿子表,而用户表则是运动表的父表)

运动表
[java] view plain copy
@Entity
public class SportInfo {
@Id
private Long sportId;
//日期
private String date = “”;
private Long UserId;
@ToOne(joinProperty = “UserId”)
private UserInfo userInfo;//关系表
}
用户表
[java] view plain copy
@Entity
public class UserInfo {
@Id
private Long id;
//账号
private String number;
//密码
private String password;
//昵称
private String nick_name;
//一对多关联
@ToMany(referencedJoinProperty = “sportId”)
private List sportInfo;
}
多表关联的增删改查(我已封装成了方法方便使用)
[java] view plain copy
public class DataBaseTool {

private static SportInfoDao mSportInfoDao = MyApplication.getInstances().getDaoSession().getSportInfoDao();  
private static UserInfoDao mUserInfoDao = MyApplication.getInstances().getDaoSession().getUserInfoDao();  
/** 
 * 增加运动信息 
 */  
public static long insertSportInfo(UserInfo userInfo,SportInfo sportInfo)  
{  
    sportInfo.setUserId(userInfo.getId());//增加运动表时要指定其父表(用户表id和用户表)  
    sportInfo.setUserInfo(userInfo);  
    return mSportInfoDao.insertOrReplace(sportInfo);  
}  
/** 
 * 增加用户信息 
 */  
public static long insertUserInfo(UserInfo info)  
{  
    return mUserInfoDao.insertOrReplace(info);  
}  

/** 
 * 查运动信息 
 */  
public static List<SportInfo> SearchSportInfo(UserInfo userInfo)  
{  
    return userInfo.getSportInfo();//查找运动表则需要通过用户表来获取运动表的集合然后再遍历找到所需运动表  
}  

/** 
 * 查用户信息 
 */  
public static List<UserInfo> SearchUserInfo()  
{  
    //惰性加载  
    List<UserInfo> list = mUserInfoDao.queryBuilder().listLazy();  
    return list;  
}  

/** 
 * 删除某条用户信息 
 * @param i 删除数据的id 
 */  
public static void deleteUserInfo(long i)  
{  
    mUserInfoDao.deleteByKey(i);  
    //当然Greendao还提供了其他的删除方法,只是传值不同而已  
}  

/** 
 *修改某条运动信息 
 */  
public static void correctSportInfo(SportInfo info)  
{  
    mSportInfoDao.update(info);  
}  

/** 
 *修改某条用户信息 
 */  
public static void correctUserInfo(UserInfo info)  
{  
    mUserInfoDao.update(info);  
}  

}

四、Greendao注解含义

(1)@Entity 实体标识
@nameInDb 在数据库中的名字,如不写则为实体中类名
@indexes 索引
@createInDb 是否创建表,默认为true,false时不创建
@schema 指定架构名称为实体
@active 无论是更新生成都刷新
(2)@Id 每条数据对应的位置,必写项
(3)@Property(nameInDb = “”) 表示该属性将作为表的一个字段,其中nameInDb属性值是在数据库中对应的字段名称,可以自定义字段名,例如可以定一个跟实体对象字段不一样的字段名
(4)@NotNull 不为null
(5)@Unique 唯一约束 该属性值必须在数据库中是唯一值
(6)@ToMany 一对多
(7)@OrderBy 排序
(8)@ToOne 一对一 关系表
(9)@Transient 不保存于数据库
(10)@generated 由greendao产生的构造函数或方法

五、Greendao特性

精简
高效率
低功耗
使用方便

ASimpleCache

2 封装了哪些常用类型的缓存
String类型
Bitmap
JSONArray
JSONObject
Serializable

官方介绍
ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架。轻量到只有一个java文件(由十几个类精简而来)。

1、它可以缓存什么东西?
普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据。

2、它有什么特色?
特色主要是:
1:轻,轻到只有一个JAVA文件。
2:可配置,可以配置缓存路径,缓存大小,缓存数量等。
3:可以设置缓存超时时间,缓存超时自动失效,并被删除。
4:支持多进程。

3、它在android中可以用在哪些场景?
1、替换SharePreference当做配置文件
2、可以缓存网络请求数据,比如oschina的android客户端可以缓存http请求的新闻内容,缓存时间假设为1个小时,超时后自动失效,让客户端重新请求新的数据,减少客户端流量,同时减少服务器并发量。

4、如何使用 ASimpleCache?
以下有个小的demo,希望您能喜欢:

ACache mCache = ACache.get(this);
mCache.put(“test_key1”, “test value”);
mCache.put(“test_key2”, “test value”, 10);//保存10秒,如果超过10秒去获取这个key,将为null
mCache.put(“test_key3”, “test value”, 2 * ACache.TIME_DAY);//保存两天,如果超过两天去获取这个key,将为null
1
2
3
4
获取数据

ACache mCache = ACache.get(this);
String value = mCache.getAsString(“test_key1”);

数据缓存策略

数据实时性高
常见的此类应用:新闻、朋友圈、股票、社区等。
无论是否存在缓存,都应该去请求网络,缓存只是充当了一个“默认数据”的角色。也就是先显示缓存数据,然后请求网络,显示最新的数据。

伪代码如下:

如果 (存在缓存) {
读取缓存并显示
}
请求网络
写入缓存
显示网络数据

流程很简单,但其中存在很多细节。比如,如果缓存可用,请求网络的时候,不应该显示正在加载的界面,网络请求失败的时候,也不应该显示错误界面。
每个数据请求,都包含大量的逻辑判断和分支,你完全可以这样实现,但这样的代码不够优雅,在下一篇文章 RxJava2.0在安卓中的二级缓存策略 我将会介绍用 RxJava2.0 实现此类数据缓存。

数据定期更新或不频繁变化
常见的此类应用:应用市场、小说、定期更新的干货类
这类应用,根据情况,对缓存的数据设置一个过期时间,只要时间未过期,就优先使用缓存,当缓存过期后,优先使用网络。

伪代码如果:

如果 (存在缓存 且 缓存未过期) {
读取缓存并显示
返回
}
请求网络
更新缓存
显示最新数据

这类应用逻辑就更简单,要么显示缓存数据,要么请求网络。同样,下一篇文章我会介绍 RxJava2.0 的实现方式。

DiskLruCache

https://blog.csdn.net/easyer2012/article/details/53931708

Dropbox、Twitter、网易新闻等都是使用DiskLruCache来进行硬盘缓存的,其中Dropbox和Twitter大多数人应该都没用过,那么我们就从大家最熟悉的网易新闻开始着手分析,来对DiskLruCache有一个最初的认识吧。

其实DiskLruCache并没有限制数据的缓存位置,可以自由地进行设定,但是通常情况下多数应用程序都会将缓存的位置选择为 /sdcard/Android/data//cache 这个路径。选择在这个位置有两点好处:第一,这是存储在SD卡上的,因此即使缓存再多的数据也不会对手机的内置存储空间有任何影响,只要SD卡空间足够就行。第二,这个路径被Android系统认定为应用程序的缓存路径,当程序被卸载的时候,这里的数据也会一起被清除掉,这样就不会出现删除程序之后手机上还有很多残留数据的问题。

第一种: 使用SharedPreferences存储数据
  适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码等
  核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data//shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,第二个参数具体如下:
  Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。
  Context.MODE_WORLD_READABLE: 指定该SharedPreferences数据能被其他应用程序读,但不能写。
  Context.MODE_WORLD_WRITEABLE: 指定该SharedPreferences数据能被其他应用程序读,写
  SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
第二种: 文件存储数据
  可以在设备本身的存储设备或者外接的存储设备中创建用于保存数据的文件。同样在默认的状态下,文件是不能在不同的程序间共享。
  写文件:调用Context.openFileOutput()方法根据指定的路径和文件名来创建文件,这个方法会返回一个FileOutputStream对象。
  读取文件:调用Context.openFileInput()方法通过制定的路径和文件名来返回一个标准的Java FileInputStream对象。
第三种:SQLite存储数据
  SQLite Database数据库。Android对数据库的支持很好,它本身集成了SQLite数据库,每个应用都可以方便的使用它,或者更确切的说,Android完全依赖于SQLite数据库,它所有的系统数据和用到的结构化数据都存储在数据库中。 它具有以下优点: a. 效率出众,这是无可否认的 b. 十分适合存储结构化数据 c. 方便在不同的Activity,甚至不同的应用之间传递数据。  
第四种:ContentProvider
  Android系统中能实现所有应用程序共享的一种数据存储方式,由于数据通常在各应用间的是互相私密的,所以此存储方式较少使用,但是其又是必不可少的一种存储方式。例如音频,视频,图片和通讯录,一般都可以采用此种方式进行存储。每个ContentProvider都会对外提供一个公共的URI(包装成Uri对象),如果应用程序有数据需要共享时,就需要使用ContentProvider为这些数据定义一个URI,然后其他的应用程序就通过Content Provider传入这个URI来对数据进行操作。
  总结一下,文件适用于存储一些简单的文本数据或者二进制数据,SharedPreferences适用于存储一些键值对,而数据库则适用于那些复杂的关系型数据。

ROOM

  Android 2017 IO大会推出了官方数据库框架:Room。Room其实就只是对原生的SQLite API进行了一层封装。

简单使用:

和常规的ORM框架一样,让Entity对应数据库表,然后通过添加编译期注解来进行表和字段的配置,例如:
@Entity
public class Student implements Serializable {
@PrimaryKey
public int id;

@ColumnInfo(name = "student_name")
public String name;

@Embedded(prefix = "address_")
public Address address;

}
1
2
3
4
5
6
7
8
9
10
11
用抽象DAO类来定义数据库的CRUD操作,例如:
@Dao
public abstract class StudentDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract void insert(Student… students);

@Delete
public abstract void delete(Student... students);

@Update
public abstract void update(Student... students);

@Query("DELETE FROM Student")
public abstract void deleteAll();

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
AppDatabase对应数据库,同时用来提供DAO类
@Database(entities = {Student.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase{
public abstract StudentDao studentDao();
}
1
2
3
4
调用范例
AppDatabase mDatabase = Room.databaseBuilder(this, AppDatabase.class, “app”).addMigrations().build();
StudentDao dao = mDatabase.studentDao();
Student student = new Student();
student.id = 111;
students.add(student);
1
2
3
4
5
原理: 在编译时,使用annotationProcessor来解析被@Database和@Dao标注的类,在build/generated/source/apt里生成具体的Impl类,相比于SQLite API,一定程度上减少了我们创建表和部分CRUD书写的代码量。

优点:
1. 分层清晰,上手简单,代码相比于第三方也更加可靠
2. 非基于运行时注解,仅对SQLite API进行简单封装,效率没问题
3. 存储对象里嵌套对象时,可使用@Embedded注解进行自动拆分存储。Room会把被嵌套对象里的字段放置存储对象对应的表里,例如上例,Student表里不仅会有id和name字段,还会有address对象里的所有字段。这样就可以不用通过外键关联多表了。

缺点:
1. 查询和需要判断条件的删改都免不了要写SQL语句,虽然Room把语句拼写错误的提示提前到了编译时,但仍然需要关心表名、字段名等
2. 数据库升级无法自动且未提供友好API,同样需要写SQL语句,开发者手动写”ALTER table”在多表外键关联时容易出错。

猜你喜欢

转载自blog.csdn.net/feather_wch/article/details/80414245
今日推荐