基础知识
基础知识来自《Android组件化架构》仓王著 一书。
Android的数据存储方式有哪些?
Android的5中存储方式:
· SharedPreferences(配置共享)
· File I/O(文件存储):内存和外部存储
· SQLite(数据库):数据库操作,数据库增删改查
· ContentProvider(内容提供者):用于跨进程数据共享,进程间通信
· 网络存储:上传数据和网络请求数据
数据存储的三个维度
存储方式 | 安全 | 效率 | 量级 |
---|---|---|---|
网络存储 | 丢包、拦截问题 | 写入和读取网络环境速度 | 无限大 |
File I/O | sd 内存 | 存储大型数据文件 | SD卡内存 |
SQLite | App内 | 管理数据处理最高效,不用于保存大数据文件 | 数据表格 |
ContentProvider | App外标识符分辨 | 跨App传输数据,速度取决于存储数据的获取的类型和大小 | 取决于存储体 |
SharedPreferences | App内 | 配置存储,并非专业用于数据持久化存储 | 配置XML |
安全、效率、量级决定我们使用哪种存储方式。
安全上
SQLite > SharedPreferences > ContentProvider > File I/O > 网络存储
SQLite的安全性最高,除了ContentProvider和本App,没有其他访问方式。持有相同的ShareUid、SharedPreferences可以被访问。ContentProvider是只要持有相同的标识符就能共享数据。而File I/O保存在App内,只要知道App内路径就能查看到。网络存储的安全性是最低的。
效率上
SQLite > SharedPreferences = File I/O > ContentProvider > 网络存储
量级上
网络存储 > File I/O > ContentProvider = SQLite > SharedPreferences
五种存储方式的基本原理
网络存储
使用HTTP协议或者Socket通信作为传输方式。(HTTP底层也是通过短时间的Socket通信来实现的传输)。我们通过目前流行的网络框架(如OkHttp、retrofit、volley等)来发送接收数据。其数据格式一般为XML、JSON格式。
File I/O
操作数据通过字节流操作来完成,直接对二进制数据进行处理。
SQLite
SQLite是轻量级数据库。通过SQLiteOpenHelper来封装入口,然后调用SQLiteDataBase进行操作。
ContentProvider
ContentProvider可以用于不同的应用程序共享数据,其数据的暴露方式是采取类似数据库中表的方法。而ContentResolver恰好采用类似数据库的方法从Content Provider中存取数据,它通过Uri的来查询ContentProvider中提供的数据。
SharedPreferences
SharedPreferences是一种轻量级的数据存储方式,它将一些简单数据类型的数据,包括boolean、int、float、long和String类型的数据,以键值对的形式存储在应用程序的私有SharedPreferences目录(/data/data/<包名>/shared_prefs/)中。通过将键值以XML格式保存到私有的XML文件中。
greenDao
简介
greenDao是一个热门的ORM(Object Relational Mapping,对象关系映射)数据库框架。greenDao能够提供一个接口,通过操作对象的方式去操作关系型数据库,操作数据库更简单、更方便。底层通过操作SQLiteDatebase来完成数据库操作。
greenDao是目前众多ORM数据库中最稳定、速度最快、编写体验最好的框架,并且支持RxJava。
greenDao的优点:
- 性能高,号称Android最快的关系型数据库。
- 内存占用小。
- 库文件比较小,小于100KB,编译时间短,而且可以避免65K方法数限制。
- 支持数据库加密,greenDao支持SQLCipher进行数据库加密。
- 简洁易用的API。
greenDao的使用
- gradle配置
// In your root build.gradle file:
buildscript {
repositories {
jcenter()
mavenCentral() // add repository
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.1'
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
}
}
// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin
dependencies {
implementation 'org.greenrobot:greendao:3.2.2' // add library
}
如果有新版本,将上面的版本号(3.2.2)替换。
- 实体类
我们简单的使用三个注解:
@Entity 声明实体对象;
@Id 声明索引Id;
@Property 声明每个对象带有的列名(columnName),默认为@Property(nameInDb = “name”)。
如下代码
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Property;
import org.greenrobot.greendao.annotation.Generated;
@Entity
public class User {
@Id
@Property(nameInDb = "_id")
private Long id;
@Property(nameInDb = "name")
private String name;
@Property(nameInDb = "sex")
private String sex;
@Property(nameInDb = "age")
private int age;
}
第一次编译会生成DaoMaster、DaoSession和数据类名Dao(如上代码即UserDao)文件。(第一次编译Bean里没有setter/getter方法,会自动生成)
可在下面路径中找到生成的DaoMaster、DaoSession和数据类名Dao。
app\build\generated\source\greendao\<包名>\<实体类所在包名>\
- 初始化
//do this once, for example in your Application class
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, dbName, null);
SQLiteDatabase db = helper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(db);
DaoSession daoSession = daoMaster.newSession();
//do this in your activities/fragments to get hold of a DAO (Data Access Object 数据访问对象)
//通过DaoSession获得具体的DAO
daoSession.getUserDao();
- 使用
//通过DaoSession获得具体的DAO
UserDao mUserDao = daoSession.getUserDao();
//插入数据
mUserDao.insert(new User(1L, "张三", "男", 23));
mUserDao.insert(new User(2L, "张三", "男", 26));
mUserDao.insert(new User(3L, "王五", "男", 13));
//查询数据
//User user = mUserDao.queryBuilder().where(UserDao.Properties.Name.eq("张三")).unique();
//Log.i(TAG, "queried user: " + user.toString());
List<User> list = mUserDao.queryBuilder().where(UserDao.Properties.Name.eq("张三")).list();
for (User user : list) {
Log.i(TAG, "queried user: " + user.toString());
}
代码中的Name类型是Property,它封装一些条件函数,返回WhereCondition(where条件),非常的简单易用。
下面是Property的源码:
package org.greenrobot.greendao;
import java.util.Collection;
import org.greenrobot.greendao.internal.SqlUtils;
import org.greenrobot.greendao.query.WhereCondition;
import org.greenrobot.greendao.query.WhereCondition.PropertyCondition;
/**
* Meta data describing a property mapped to a database column; used to create WhereCondition object used by the query builder.
*
* @author Markus
*/
public class Property {
public final int ordinal;
public final Class<?> type;
public final String name;
public final boolean primaryKey;
public final String columnName;
public Property(int ordinal, Class<?> type, String name, boolean primaryKey, String columnName) {
this.ordinal = ordinal;
this.type = type;
this.name = name;
this.primaryKey = primaryKey;
this.columnName = columnName;
}
/** Creates an "equal ('=')" condition for this property. */
public WhereCondition eq(Object value) {
return new PropertyCondition(this, "=?", value);
}
/** Creates an "not equal ('<>')" condition for this property. */
public WhereCondition notEq(Object value) {
return new PropertyCondition(this, "<>?", value);
}
/** Creates an "LIKE" condition for this property. */
public WhereCondition like(String value) {
return new PropertyCondition(this, " LIKE ?", value);
}
/** Creates an "BETWEEN ... AND ..." condition for this property. */
public WhereCondition between(Object value1, Object value2) {
Object[] values = { value1, value2 };
return new PropertyCondition(this, " BETWEEN ? AND ?", values);
}
/** Creates an "IN (..., ..., ...)" condition for this property. */
public WhereCondition in(Object... inValues) {
StringBuilder condition = new StringBuilder(" IN (");
SqlUtils.appendPlaceholders(condition, inValues.length).append(')');
return new PropertyCondition(this, condition.toString(), inValues);
}
/** Creates an "IN (..., ..., ...)" condition for this property. */
public WhereCondition in(Collection<?> inValues) {
return in(inValues.toArray());
}
/** Creates an "NOT IN (..., ..., ...)" condition for this property. */
public WhereCondition notIn(Object... notInValues) {
StringBuilder condition = new StringBuilder(" NOT IN (");
SqlUtils.appendPlaceholders(condition, notInValues.length).append(')');
return new PropertyCondition(this, condition.toString(), notInValues);
}
/** Creates an "NOT IN (..., ..., ...)" condition for this property. */
public WhereCondition notIn(Collection<?> notInValues) {
return notIn(notInValues.toArray());
}
/** Creates an "greater than ('>')" condition for this property. */
public WhereCondition gt(Object value) {
return new PropertyCondition(this, ">?", value);
}
/** Creates an "less than ('<')" condition for this property. */
public WhereCondition lt(Object value) {
return new PropertyCondition(this, "<?", value);
}
/** Creates an "greater or equal ('>=')" condition for this property. */
public WhereCondition ge(Object value) {
return new PropertyCondition(this, ">=?", value);
}
/** Creates an "less or equal ('<=')" condition for this property. */
public WhereCondition le(Object value) {
return new PropertyCondition(this, "<=?", value);
}
/** Creates an "IS NULL" condition for this property. */
public WhereCondition isNull() {
return new PropertyCondition(this, " IS NULL");
}
/** Creates an "IS NOT NULL" condition for this property. */
public WhereCondition isNotNull() {
return new PropertyCondition(this, " IS NOT NULL");
}
}