这是我参与「第四届青训营 」笔记创作活动的第五天
本文用于记录我在字节跳动青训营学习到的有关Android数据存储方面的知识
存储方式
常见的数据持久化存储大致分为一下四种。
SharedPreferences 常用于保存APP的各种配置,例如登录模块的是否记住密码、是否自动登录等。
文件存储 常用于保存文件。
ContentProvider 跨APP进行数据共享,常用于读取系统应用的数据,例如图库。
SQLite 数据库常用于存储结构化数据,也是较为重要的一种数据存储方式。
数据库存储
Android提供了可以直接操作SQLite的一套接口,但是其往往比较复杂,所以在实际应用中,多数选择使用相关框架,加快开发速度。
常用的SQLite框架有三种,下面是他们之间的一些对比
在这里我记录一下在这次大作业中,团队使用到的Room框架的使用方法。
Room
在这里我们使用的Java + Room + RxJava
第一步:引依赖
def room_version = "2.4.3"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// RxJava依赖
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation "androidx.room:room-rxjava3:$room_version"
第二步:编写实体类
@Entity(tableName = "listData_table", primaryKeys = {"id", "version"})
public class ListData {
public static final int MOVIE_TYPE = 1;
public static final int TELEPLAY_TYPE = 2;
public static final int VARIETY_TYPE = 3;
@NonNull
public String id = "";
/**
* 榜单期数,一周一期
*/
@NonNull
public Integer version = 0;
/**
* 演员
*/
public List<String> actors;
}
在实体类上需要使用@Entity 注解标明其是一个数据库实体,并设置好表名、约束等。
第三步:编写DAO接口
/**
* 对表listData_table进行数据操作
*/
@Dao
public interface IListDataDao {
/**
* 获取所有榜单数据
* @param type 数据类型 {@link ListData#type ListData.type}
* @param version 榜单版本
* @return 榜单数据
*/
@Query("select * from listData_table where type = :type and version = :version")
Single<List<ListData>> getListData(Integer type, Integer version);
/**
* 插入榜单数据集合
* @param listData 需要插入的榜单数据集合
* @return 异步操作对象
*/
@Insert
Completable insertList(List<ListData> listData);
}
注意:这里如果在Sql中需要引入方法参数,使用的是 : ,和后端JDBC使用的 # $ 不同。Sql语句和后端Mysql等的差不多。
在这里可以直接标明一个@Insert表示插入数据,可以是一条,也可以是集合
第四步:定义数据库对象
@Database(entities = {ListData.class,UserOpenInfo.class},version = 2,exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
private static volatile AppDatabase instance;
private static String dbPath = "database-name";
public static AppDatabase getInstance() {
/*
获取database单例
*/
if (instance == null) {
synchronized (AppDatabase.class) {
if (instance == null) {
instance = Room.databaseBuilder(MyApplication.getAppContext(), AppDatabase.class, dbPath)
.fallbackToDestructiveMigration()
.build();
}
}
}
return instance;
}
/**
* 获取榜单dao的操作对象
* @return
*/
public abstract IListDataDao getListDataDao();
第五步:调用接口
/**
* 更新数据库中的数据
*/
private void updateDataBase(List<ListData> list, Integer type, Integer version) {
IListDataDao dao = AppDatabase.getInstance().getListDataDao();
for (ListData data :
list) {
data.version = version;
}
Single<List<ListData>> single = dao.getListData(type, version);
single.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<ListData>>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onSuccess(@NonNull List<ListData> listData) {
if (listData == null || listData.isEmpty()) {
//数据库中没有数据,直接插入数据库
dao.insertList(list).subscribeOn(Schedulers.io()).subscribe();
return;
}
dao.updateListData(list).subscribeOn(Schedulers.io()).subscribe();
}
@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG, "onError: 查询数据库失败!!!" + e.getMessage());
}
});
}
总体就是按照这五步进行,在操作数据库的时候,由于Android的特性,我们不能直接在主线程操作数据库,而需要在子线程,可以引入线程池,也可以使用异步框架,我们这里使用的就是RxJava这个框架。