利用Annotation实现Android sqlite框架
来源:互联网 发布:笔记本能开淘宝店铺 编辑:程序博客网 时间:2024/06/07 01:03
结合Annotation类的学习写了一个SQLite的框架,对数据库的操作转化为对java对象的操作,摆脱开发过程中代码与表操作混在一起的问题,其实Annotation在框架设计当中用到的比较多,常见的就是我们在方法上加@注解,我们来看看如何自定义一个Annotation类来使用它
源码及DEMO地址:https://github.com/xiaoqi0716/LightSqlite
介绍框架之前先看来看它的用法:比如我们有一个数据库用来存储学生、老师的信息,那么我们在使用时可以这么来做
写一个类继承AbstractDBHelper,并实现相就的方法
public class PersonalDB extends AbstractDBHelper { private final String DB_NAME = "MY_DB.db"; //数据库名 private final int DB_VERSION = 1; //数据库版本 public PersonalDB(Context context) { super(context); } @Override public String getDataBaseName() { return DB_NAME; } @Override public int getDataBaseVersion() { return DB_VERSION; } //返回MY_DB.db数据库所有的表,后续增加表直接在这里添加 @Override public List<AbstractTable<?>> getTables() { List<AbstractTable<?>> list = new ArrayList<AbstractTable<?>>(); list.add(StudentTable.getInstance()); //学生表 list.add(TeacherTable.getInstance()); //老师表 return list; }}
然后建立一个学生表对应的数据类
public class StudentItem { public static final String FIELD_S_ID = "s_id"; public static final String FIELD_S_NAME = "s_name"; public static final String FIELD_S_AGE = "age"; public static final String FIELD_S_CLASS = "class"; @Column(name = FIELD_S_ID, unique = true, index = true, notNull = true) private int id; @Column(name = FIELD_S_NAME, notNull = true) private String name; @Column(name = FIELD_S_AGE, notNull = true) private int age; @Column(name = FIELD_S_CLASS) private String inClass; //GET and SET .....}
public class StudentTable extends AbstractTable<StudentItem> { private final static String TABLE_NAME = "student"; // 学生表 @Override public String getTableName() { return TABLE_NAME; } // 当数据库版本号更新时,对该表的操作 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }}
老师表就不写了,与StudentTable写法一样,完成上面几步操作就可以使用了,最后看盾如何使用:
PersonalDB db = new PersonalDB(context);
db.open();
上面两条语句就初始了一个数据库打开操作,接下来如何对表进行操作:
StudentTable.getInstance().add(......); //增
StudentTable.getInstance().find(......); //查询
StudentTable.getInstance().set(......); //修改
StudentTable.getInstance().remove(......); //删除
增、删、改、查各有多种API实现来使用,是不是很简单。
框架设计思路:
数据库概念大家都比较熟悉,一个数据库下面会有多张表,这属于一对多的情况,那么体现在框架中就是一个数据库类当中,需要为它配置表对应的类对象,由数据库这个类对管理所有表。
在处理数据时,按照我们平时的习惯,应该有model类去管理一个数据模型,比如上文用的学生、老师,他们都有自己的属性,其实model类中的属性是最能体现这个表中有哪些字段,比如StudentItem这个model类,它里面有学生ID、姓名、年龄、年级等,那么对应的表也是这些字段,那么怎么才能把这些类的属性关联到表中每一个字段上呢,这里我用到了java中一个特殊的类,Annotation类,这个类其它并不陌生,比如我们平时继承父类的一些方法,开发环境往往会加上@Overide这个注解,这个实际上就一个Annotation类,关于这个类的细节这里不做详细介绍,这里主要讲怎么使用它来完成我们的框架,代码献上
我们主要看一下AbstractDBHelper类中一个创建表的方法,其它逻辑请查看源码
private void createTable(SQLiteDatabase db, AbstractTable<?> table) { StringBuilder sql = new StringBuilder(); sql.append("CREATE TABLE IF NOT EXISTS "); String tableName = table.getTableName(); sql.append(tableName).append(" ("); Class<?> tableCls = null; Type t = table.getClass().getGenericSuperclass(); if (t != null && t instanceof ParameterizedType) { Type[] type = ((ParameterizedType) t).getActualTypeArguments(); tableCls = (Class<?>) type[0]; } Field[] fields = tableCls.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); if (field.isAnnotationPresent(Column.class)) { Column ano = field.getAnnotation(Column.class); String fieldName = ano.name(); sql.append(fieldName).append(" "); sql.append(getFieldType(field)).append(" "); if (ano.primaryKey()) { sql.append("PRIMARY KEY").append(" "); } if (ano.autoIncrement()) { sql.append("AUTOINCREMENT").append(" "); } if (ano.unique()) { sql.append("UNIQUE").append(" "); } if (ano.notNull()) { sql.append("NOT NULL").append(" "); } if (!TextUtils.isEmpty(ano.defaultVal())) { String fieldType = getFieldType(field); if ("TEXT".equals(fieldType)) { sql.append("default").append(" ").append("'").append(ano.defaultVal()).append("'").append(" "); } else { sql.append("default").append(" ").append(ano.defaultVal()).append(" "); } } sql.append(", "); } } sql.deleteCharAt(sql.length() - 2); sql.append(")"); LogUtils.v(sql.toString()); try{ db.execSQL(sql.toString()); }catch (Exception e) { e.printStackTrace(); } for (Field field : fields) { field.setAccessible(true); if (field.isAnnotationPresent(Column.class)) { Column an = field.getAnnotation(Column.class); if (an.index()) { String sqlStr = "CREATE INDEX IF NOT EXISTS " + table.getTableName() + "_" + an.name() + "_index ON " + table.getTableName() + "(" + an.name() + ")"; LogUtils.v(sqlStr); try{ db.execSQL(sqlStr); }catch (Exception e) { e.printStackTrace(); } } } } table.onCreateTrigger(db); }
该方法接收两个参数,其中一个是继承AbstractTable类的实例,在方法内部通过Type t = table.getClass().getGenericSuperclass();,Type[] type = ((ParameterizedType) t).getActualTypeArguments(); Type是Java 中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。ParameterizedType参数化类型,就是所说的泛型,(Class<?>) type[0]拿到了传入泛型的真实类型,type它是一个数组,由于我们只用到一个参数,如上面看的StudentTable类,所以只取第0个,就是StudentItem这个类。当我们拿到了StudentItem我们就可以对它进行反射,field.isAnnotationPresent(Column.class);这句来判断某些属性是否加上了@Column注解,如果有才认为是字段相关的属性,Column ano = field.getAnnotation(Column.class);拿到了Column注解这个类的实例,后面就是对@Column中参数进行解析了。
我们来看看@Column这个是怎么定义的呢
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface Column { String name(); boolean primaryKey() default false; boolean autoIncrement() default false; boolean unique() default false; boolean index() default false; boolean notNull() default false; String defaultVal() default "";}
Column 是一个自定义Annotation类,@interface是自定义Annotation的写法,这个类本身也有两个注解修饰
@Target(ElementType.METHOD) 修饰的注解表示该注解只能用来修饰在方法上。
@Target(ElementType.FIELD)表示@Column这个注解只能用在属性上
@Retention(RetentionPolicy.CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候;
@Retention(RetentionPolicy.SOURCE )修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中;
@Retention(RetentionPolicy.RUNTIME )修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时,
本框架中的逻辑是在运行时使用,所以使用RetentionPolicy.RUNTIME
利用Annotation来实现表和类的属性关联,减少了在开发过程中不用刻意地去再定义一次字段的属性值了,充分利用现有的可用的数据
源码及DEMO地址:https://github.com/xiaoqi0716/LightSqlite
- 利用Annotation实现Android sqlite框架
- 轻量级的利用Annotation方式实现Android SQLite的框架
- 【Android数据库优化】利用注解实现SQLite通用框架抽取
- Android懒人框架Android annotation
- android利用annotation代替findViewById()
- android之利用SQLite数据库实现登陆和注册
- Android之利用SQLite数据库实现登陆和注册
- android之利用SQLite数据库实现登陆和注册
- android之利用SQLite数据库实现登陆和注册
- Android之利用SQLite数据库实现登陆和注册
- Android Annotation框架初步实践
- android sqlite orm框架
- Android sqlite 使用框架
- 利用liyfmdb框架,实现本周,本月,本日,本季度,本年的sqlite查询
- 利用 annotation 命令实现图形的标注
- 利用Annotation方式实现AOP编程
- Spring3+hibernate4利用Annotation实现事务
- 利用Annotation和Aop实现日志记录
- 精通 Android Data Binding
- 差分约束 poj1364
- 学习 Perl(一) —— 安装及 hello world
- java基础6(代码)
- Lua table(表)
- 利用Annotation实现Android sqlite框架
- cast(转化)总结
- #greendao#NoClassDefFoundError:
- Android Studio 使用小技巧和快捷键
- spring bean装配(bean的作用域、bean的生命周期、Aware接口、Bean的自动装配Autowiring、资源文件Resources )
- Android干货·收集站
- Java中ArrayList和LinkedList区别
- HorzontallListview与scrollview冲突解决
- log4net输出日志