1.涉及知识

反射 工厂模式 单例
关于工厂模式:抽象工厂用于创建相对复杂的对象,适用于对象包含很多零件或生产大批对象的情景
关于泛型:
泛型方法

public class Test {public static <T> T init(String s, Class<T> clazz){s = clazz.getSimpleName();System.out.println("s "+s);return null;}class Person{}public static void main(String[] args) {init(new String(), Person.class);}}

输出

s Person
public static <T> T init(String s, Class<T> clazz)中

<T>是声明泛型. 第二个T代表返回对象类型为T .Class<T> clazz代表传入参数是T的class
泛型类的使用

public interface IDaoSupport<T>{}

一般泛型类/接口在类名之后就会加上 这里是泛型的声明 之后即可在类中是泛型T

2.缓存方案

我们知道访问数据库 访问网络都是比较耗时的,但是一般由于数据量较大,不可能全部缓存到本地,因此访问网络和数据库有些情况还是必不可少的,那么我们应该尽量减少从用户操作到用户看到返回结果之间的时间
为了提高搜索效率 ,有一些优化缓存的方案

当然现在一些http框架还会自带缓存,比如OKHttp 针对不同的网络框架,可能有不同的缓存方案。但是我们设计的缓存方案,应该是尽量通用的。
另外,缓存也可以设置定期清除的策略,避免空间被无用数据占用太多的空间
我们本节的代码主要是上面黑色箭头的第一步:查看本地是否有缓存的部分,说的简单一点,其实就是数据库的CURD
下面我们就进入数据库操作的学习

3.类结构

4.代码展示

Model类

public class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}
}

数据库支持类接口

public interface IDaoSupport<T> {// 初始化数据库表(Class<T> clazz代表T所对应的类)void init(SQLiteDatabase sqLiteDatabase, Class<T> clazz);// 数据库插入数据public long inert(T t);public void deleteAll();}

辅助类

class DaoUtil {private static final String TAG = "DaoUtil";// 获取数据库表名public static String getTableName(Class<?> clazz) {return clazz.getSimpleName();}// 将java中的基本数据类型翻译为SQL语句中的数据类型// 此方法只适用于属性中的基本类型 如果存在复杂类型(如User Student)等 则不适用该方法public static String getColumnType(String type) {String value = null;if (type.contains("String")) {value = " text";} else if (type.contains("int")) {value = " integer";} else if (type.contains("boolean")) {value = " boolean";} else if (type.contains("float")) {value = " float";} else if (type.contains("double")) {value = " double";} else if (type.contains("char")) {value = " varchar";} else if (type.contains("long")) {value = " long";} else {Log.e(TAG, "getColumnType: invalid type!");}return value;}
}

数据库支持类实现类

class DaoSupport<T> implements IDaoSupport<T> {// 数据库对象private SQLiteDatabase mSqLiteDatabase;// 数据库需要操作的 表中存储的 对象类型private Class<T> mClazz;private String TAG = "DaoSupport";public DaoSupport(SQLiteDatabase sqLiteDatabase, Class<T> clazz) {init(sqLiteDatabase, clazz);}@Overridepublic void init(SQLiteDatabase sqLiteDatabase, Class<T> clazz) {this.mSqLiteDatabase = sqLiteDatabase;this.mClazz = clazz;// 创建表的sql语句/*create table if not exists Person (id integer primary key autoincrement, name text, age integer, flag boolean)*/StringBuilder sb = new StringBuilder();sb.append("create table if not exists ").append(DaoUtil.getTableName(mClazz))// 表名为类的名字.append("(id integer primary key autoincrement, ");// id 为 int的主键 自增长// 通过反射获取类中的属性Field[] fields = mClazz.getDeclaredFields();for (Field field : fields) {//遍历属性field.setAccessible(true);// 设置权限String name = field.getName();String type = field.getType().getSimpleName();// int String boolean//  type需要进行转换 int --> integer, String text;sb.append(name).append(DaoUtil.getColumnType(type)).append(", ");}// 将插入语句的最后两位", "替换为")"sb.replace(sb.length() - 2, sb.length(), ")");String createTableSql = sb.toString();Log.e(TAG, "建表语句--> " + createTableSql);// 执行建表语句mSqLiteDatabase.execSQL(createTableSql);}// 插入数据库 类型为任意类型@Overridepublic long inert(T t) {/*通常我们可能直接调用ContentValues values = new ContentValues();values.put("name","wz");values.put("author","xx");values.put("price",1.0);db.insert("Book",null,values);但是这样其实不方便 如果我们删除或增加Book.java的字段 那么这段代码需要修改并且 对于不同的对象 我们还需要写不同的插入逻辑,利用反射 就可以直接绕开这两个问题因此 这里我们使用了反射*/ContentValues values = contentValuesByObj(t);return mSqLiteDatabase.insert(DaoUtil.getTableName(mClazz), null, values);}@Overridepublic void deleteAll() {mSqLiteDatabase.execSQL("DROP TABLE " + DaoUtil.getTableName(mClazz));//mSqLiteDatabase.execSQL("DELETE FROM " + DaoUtil.getTableName(mClazz));}// 查询// 修改// 删除// obj 转成 ContentValues// ContentValues实际作用类似与hashMap 只不过它的value只能push基本类型private ContentValues contentValuesByObj(T obj) {ContentValues contentValues = new ContentValues();// 通过反射获取mClazz定义的filed(以Person为例 返回的是age 和 name字段)Field[] fields = mClazz.getDeclaredFields();for (Field field : fields) {Method putMethod;try {// 设置权限,私有和共有都可以访问field.setAccessible(true);// 获取field的名称(如age)String key = field.getName();// 获取field的value(如30)Object value = field.get(obj);// 虽然使用反射会有一点性能的影响 但是影响很小// 而且源码里面  activity实例的创建 View创建反射等都使用了反射// 因此这里也会使用反射 获取put方法// (如ContentValues.class.getDeclaredMethod("put",String.class, java.lang.Integer))// 代表希望调用的是put(String key, Integer value)的方法putMethod = ContentValues.class.getDeclaredMethod("put",String.class, value.getClass());// 通过反射执行ContentValues的putXXX方法// 相当于调用类似 contentValues.put("age",30);putMethod.invoke(contentValues, key, value);} catch (Exception e) {e.printStackTrace();}}return contentValues;}
}

工厂类

public class DaoSupportFactory {private static final String TAG = "DaoSupportFactory";// 单例对象private static DaoSupportFactory mFactoryInstance;private final SQLiteDatabase mSqLiteDatabase;private DaoSupportFactory(Context context) {// 把数据库放到内存卡里面  TODO 没有判断是否有存储卡 没有动态申请权限// path:/storage/emulated/0/Android/data/com.example.learneassyjoke/files/nhdz/databaseFile dbRoot = new File(context.getExternalFilesDir(null).getAbsolutePath() + File.separator + "nhdz" + File.separator + "database");if (!dbRoot.exists()) {if (!dbRoot.mkdirs()) {Log.e(TAG, "DaoSupportFactory: 创建db路径失败");};}File dbFile = new File(dbRoot, "nhdz.db");// 打开或者创建一个数据库 并存储数据库操作的引用Log.e(TAG, "DaoSupportFactory: 创建db路径==>" + dbRoot);mSqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(dbFile, null);}public static DaoSupportFactory getFactoryInstance(Context context) {if (mFactoryInstance == null) {synchronized (DaoSupportFactory.class) {if (mFactoryInstance == null) {mFactoryInstance = new DaoSupportFactory(context);}}}return mFactoryInstance;}// 获取DAO对象 用于操作数据库public <T> IDaoSupport<T> getDao(Class<T> clazz) {return new DaoSupport<>(mSqLiteDatabase, clazz);}
}

测试插入数据

        IDaoSupport<Person> daoSupport = DaoSupportFactory.getFactoryInstance(MainActivity.this).getDao(Person.class);// 最少的知识原则new Thread(() -> {long startTime = System.currentTimeMillis();int totalNum = 1000;for (int i = 0; i < totalNum; i++) {daoSupport.inert(new Person("hjcai", i));}long endTime = System.currentTimeMillis();Log.e(TAG, " insert " + totalNum + " cost time -> " + (endTime - startTime));}).start();

测试删表

IDaoSupport<Person> daoSupport = DaoSupportFactory.getFactoryInstance(MainActivity.this).getDao(Person.class);daoSupport.deleteAll();

5.主要调用流程

在activity中调用DaoSupportFactory.getFactoryInstance:触发DaoSupportFactory单例的创建 其构造方法中会在指定目录创建数据库nhdz.db(如果有必要)并获取sqlite的操作引用
接着调用getDao:将之前获取的sqlite传入IDaoSupport的实现类DaoSupport DaoSupport自动调用初始化方法,而后利用反射创建表Person,其中的数据字段均由反射得来
测试方法DaoSupport inert则先通过反射将具体的Person实例转换为ContentValues对象(ContentValues实际上就是一个Map 里面有一个个键值对)然后调用数据库操作的引用的insert方法将数据插入,当然我们也可以使用execSQL来执行插入操作
deleteAll则是直接执行删除语句

6.测试结果

2021-03-17 20:23:59.857 8159-8211/com.example.learneassyjoke E/MyActivity:  insert 1000 cost time -> 5206
2021-03-17 20:24:31.277 8227-8251/com.example.learneassyjoke E/MyActivity:  insert 1000 cost time -> 5216
2021-03-17 20:24:44.300 8264-8288/com.example.learneassyjoke E/MyActivity:  insert 1000 cost time -> 5976
2021-03-17 20:25:00.142 8300-8324/com.example.learneassyjoke E/MyActivity:  insert 1000 cost time -> 5776

可以看到平均插入1000条数据耗时5.7s左右,耗时还是比较大的
下一节将讨论如何进行数据库插入的优化

红橙Darren视频笔记 缓存方案 缓存到数据库(数据库操作) 上相关推荐

  1. 红橙Darren视频笔记 热更新 bsdiff bspatch 在Android设备上的应用 架构篇1完结篇

    概述 当时红橙的视频讲解就差不多90分钟,但是真正自己做出来热更新的demo还是花了八九个晚上,期间遇到各种各样的问题,什么叫台上一分钟 台下十年功是深有体会了. 本节会涉及一部分NDK的知识 推荐阅 ...

  2. 红橙Darren视频笔记 条件查询 删除 更新,数据库结合http做缓存机制(数据库操作)下

    查询 更新 删除的实现 修改IDaoSupport接口部分 删除查询部分 增加返回查询支持类接口 增加删除更新的接口 // 获取专门查询的支持类 按照语句查询QuerySupport<T> ...

  3. 红橙Darren视频笔记 代理模式 动态代理和静态代理

    红橙Darren视频笔记 代理模式 动态代理和静态代理(Android API 25) 关于代理模式我之前有过相关的介绍: https://blog.csdn.net/u011109881/artic ...

  4. 红橙Darren视频笔记 Behavior的工作原理源码分析

    主要coordinatorlayout的代码来自coordinatorlayout-1.0.0-sources.jar 本文从源码介绍 CoordinatorLayout 的 behavior 怎么工 ...

  5. 红橙Darren视频笔记 类加载机制(API28) 自己写个热修复 查看源码网站

    第一部分 类加载机制 一个Activity是如何被Android虚拟机找到的? 在之前的文章 红橙Darren视频笔记 自定义View总集篇(https://blog.csdn.net/u011109 ...

  6. 红橙Darren视频笔记 ViewGroup事件分发分析 基于API27

    本节目标,通过案例,先看程序运行结果,然后跟踪源码,理解为什么会有这样的输出,继而理解view group的分发机制,感觉和证明题很像呢. 考虑以下程序的运行结果: case1: public cla ...

  7. 红橙Darren视频笔记 UML图简介

    整体架构复制自红橙原视频的课堂笔记 因为他这一课没有博客,所以没有转载链接,CSDN没有转载地址是无法作为转载类型的文章发表的,暂时标记为原创 参考链接 https://blog.csdn.net/r ...

  8. 红橙Darren视频笔记 利用阿里巴巴AndFix进行热修复

    注意 由于AndFix在2017年左右就停止更新了,在最新版本的apk上遇到很多问题,我最终也没有成功进行热修复.本节主要是学习热修复的原理 在上一篇 红橙Darren视频笔记 自己捕获异常并保存到本 ...

  9. 红橙Darren视频笔记 仿QQ侧滑效果

    这一篇没有什么新的内容 就是改写 红橙Darren视频笔记 仿酷狗侧滑效果 的侧滑的效果 1.去掉淡入淡出效果 2.加上黑色模板效果 效果: 去掉淡入淡出效果很简单 就是注释掉onScrollChan ...

最新文章

  1. pku3661 Running
  2. 实验16:使用context:include-filter指定扫描包时要包含的类 实验17:使用context:exclude-filter指定扫描包时不包含的类
  3. 外网访问XAMPP失败 解决方案
  4. 谷歌对用户搜索加密这一做法对seo的影响!
  5. android mysql 数据库文件_android mysql数据库文件
  6. LOJ10155数字转换
  7. jquery背景动画插件使用
  8. 使用jquery判断及改变checkbox选中状态
  9. mongodb 学习第二天,基本操作
  10. Cuba studio框架中使用thymeteaf模板时中文乱码
  11. 维基百科 双线性插值
  12. python qq群_用Python玩转QQ群论坛
  13. 实测realme手机丢失定位功能
  14. 机票三字码,对应城市及机场一览表
  15. uni-app中使用腾旭位置服务,实现周边搜索功能,并获取到前往对应位置所需的时间(步行或驾车)
  16. 关于Github项目DCRNN运行问题小结(1)——tables模块包
  17. uClinux移植概述
  18. iot架构 mqtt netty_百度IoT:MQTT Broker架构设计
  19. 【机器学习】Kmeans聚类(含代码)
  20. SetFocus()函数

热门文章

  1. 我被C++开发欺辱的岁月
  2. 金蝶云星空使用WebAPI来新增单据
  3. 用自己电脑做服务器,建个人网站
  4. 关于eclipase出现的problems during content assist报错问题
  5. 【Win】使用L2TP出现809错误
  6. java中常量定义在interface中好还是定义在class中
  7. fastjson和json-lib的区别
  8. 作战手册-2011-12-18
  9. mysql怎么访问网页版_mysql在本地已经启动,但是在网页上不能直接访问的解决...
  10. win7文件和文件夹可以重名吗_Win7下如何重命名,替换System32文件夹下的系统文件...