- 浏览: 545712 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
q649916440:
使用这个的目的是什么呢?感觉没啥优势啊,用起来还绕个大圈
使用googleapi-client-java操作gtasks(一) -
文艺吧网:
还有一个GZIP的问题,我怎么转都乱码最后是因为要解压一下ht ...
关于使用InputStreamReader读取GBK编码文件乱码的问题 -
xiaodousa:
9楼正解!
Android在Listview中使用EditText -
fxiaozj:
zyp09 写道很想知道在Mainactivity界面怎么获得 ...
Android PreferenceActivity 学习笔记 -
zylc369:
楼主很用心,一定要顶
Android通过共享用户ID来实现多Activity进程共享
在日常开发中会遇到这种情况:
多类对象需要保存到数据库中,每类对象都要创建一个表,创建表时的字段、索引序号、字段类型都要一一对应,
如果保存到数组中,当需要增减字段就要更改数组,一是繁琐,二是很容易搞错序号导致程序运行错误,三是代码复用很难做到。
为了解决上述几点问题,在实践摸索中想出了通过annotation来解决的方法。
其原理是:
创建表时:需要表名、字段名、字段类型
保存数据时:需要表名、字段名、字段对应的值
读取数据时:需要表名、字段索引、保存值的变量
只要在进行以上操作时能提供所需要的信息,那么就能进行操作,这些信息有些可以通过类信息获得,有些则需要通过annotation传入。
1.创建annotation类,只要被此annotation类修饰的成员变量都认为是需要保存到表中的。
代码中的"##default"是自己的一个约定,当检测到此字符串时自动用变量名作为字段名,否则用指定的名字作为字段名。
2.创建一个普通的要保存到数据库中的类:
在上面的代码中:
成员变量field_all_default被用annotation标注,并都使用了默认值,那么在表中就会创建一个名为field_all_default的字段来保存此变量的值。
成员变量field_specified_primary_key被用annotation标注,并指定了是主key,不能为空,且指定了另外的字段名specified_field_name。
成员变量not_db_field没有被标注,那么就不会被保存。
3.创建一个数据库操作辅助类,在这个类的函数中会读取上面的标注信息,并根据标注信息进行处理。
3.1 创建表格:
从clazz中读取类以及annotation获取字段信息,并在指定的数据库db中创建指定的表tblName。
此函数的核心是通过遍历类的所有Field,获取字段信息:
在上面的代码中根据字段的类型得到数据表类型的调用,函数实现如下:
即根据Field的类型转换成sqlite3支持的数据类型,无需通过annotation传入了。
3.2 写数据:
就是从对象中获得值,并保存到指定的字段名中。
然后将v保存到数据表中即可。
3.3 数据库执行查询获得Cursor,将Cursor转换为对象即可:
基本的原理框架就如上所述,如果要扩充自定义类型的支持,那么修改写数据以及读取数据代码增加支持即可。
为了提高效率,可以用Hashmap将类信息、字段名和字段索引对应关系等信息缓冲,这样不必每次都通过反射获取。
多类对象需要保存到数据库中,每类对象都要创建一个表,创建表时的字段、索引序号、字段类型都要一一对应,
如果保存到数组中,当需要增减字段就要更改数组,一是繁琐,二是很容易搞错序号导致程序运行错误,三是代码复用很难做到。
为了解决上述几点问题,在实践摸索中想出了通过annotation来解决的方法。
其原理是:
创建表时:需要表名、字段名、字段类型
保存数据时:需要表名、字段名、字段对应的值
读取数据时:需要表名、字段索引、保存值的变量
只要在进行以上操作时能提供所需要的信息,那么就能进行操作,这些信息有些可以通过类信息获得,有些则需要通过annotation传入。
1.创建annotation类,只要被此annotation类修饰的成员变量都认为是需要保存到表中的。
/** * 使用此annotation指定一个成员变量为数据库的一个字段。 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface DbField { boolean primaryKey() default false; boolean notNull() default false; String fieldName() default "##default"; }
代码中的"##default"是自己的一个约定,当检测到此字符串时自动用变量名作为字段名,否则用指定的名字作为字段名。
2.创建一个普通的要保存到数据库中的类:
public class SomeThing { @DbField public String field_all_default; @DbField ( primaryKey = true, notNull = true, fieldName = "specified_field_name" ) public long field_specified_primary_key; @DbField public boolean field_boolean; public int not_db_field; }
在上面的代码中:
成员变量field_all_default被用annotation标注,并都使用了默认值,那么在表中就会创建一个名为field_all_default的字段来保存此变量的值。
成员变量field_specified_primary_key被用annotation标注,并指定了是主key,不能为空,且指定了另外的字段名specified_field_name。
成员变量not_db_field没有被标注,那么就不会被保存。
3.创建一个数据库操作辅助类,在这个类的函数中会读取上面的标注信息,并根据标注信息进行处理。
3.1 创建表格:
private void createTbl(SQLiteDatabase db, String tblName, Class<?> clazz);
从clazz中读取类以及annotation获取字段信息,并在指定的数据库db中创建指定的表tblName。
此函数的核心是通过遍历类的所有Field,获取字段信息:
for( Field f : clazz.getFields()) { if(f.isAnnotationPresent(DbField.class)) { //如果被DbField annotation标注了认为是要保存到数据表中 if(!first_field) { sql.append(", "); } DbField annotation = f.getAnnotation(DbField.class); String fieldName = annotation.fieldName(); if(fieldName.equals(DEFAULT_FIELD_NAME)) { fieldName = f.getName(); //如果是约定的默认字段名,那么用FieldName作为字段名 } sql.append(fieldName); sql.append(' '); sql.append(clazzToDbTypeString(f.getType())); //根据字段的类型得到保存到数据表中的类型 if(annotation.primaryKey()) { //判断是不是主key sql.append(" PRIMARY KEY"); } if(annotation.notNull()) { //判断是不是not null sql.append(" NOT NULL"); } first_field = false; } }
在上面的代码中根据字段的类型得到数据表类型的调用,函数实现如下:
private String clazzToDbTypeString(Class<?> clazz) { if( clazz == String.class || clazz == Character.class || clazz == char.class || clazz == Boolean.class || clazz == boolean.class) { return "TEXT"; }else if(clazz == Integer.class || clazz == int.class || clazz == Long.class || clazz == long.class || clazz == Short.class || clazz == short.class) { return "INTEGER"; }else if(clazz == Float.class || clazz == float.class || clazz == Double.class || clazz == double.class) { return "REAL"; }else { return "BLOB"; } }
即根据Field的类型转换成sqlite3支持的数据类型,无需通过annotation传入了。
3.2 写数据:
就是从对象中获得值,并保存到指定的字段名中。
ContentValues v = new ContentValues(); for( Field f : object.getClass().getFields() ) { if(f.isAnnotationPresent(DbField.class)) { //如果被标注,认为要保存到数据表中 DbField annotation = f.getAnnotation(DbField.class); String fieldName = annotation.fieldName(); if(fieldName.equals(DEFAULT_FIELD_NAME)) { fieldName = f.getName(); //如果是约定的默认字段名,那么用FieldName作为字段名 } v.put(fieldName, f.get(object).toString()); //将值和字段名配对保存 } }
然后将v保存到数据表中即可。
3.3 数据库执行查询获得Cursor,将Cursor转换为对象即可:
public Object cursorToObject(Cursor cursor, Class<?> clazz) throws Exception { Constructor<?> ct = clazz.getConstructor((Class[])null); Object sg = ct.newInstance((Object[])null); //用无参构造函数构造对象 for( Field f : clazz.getFields() ) { if(f.isAnnotationPresent(DbField.class)) { //被标注,从表中获取值 DbField annotation = f.getAnnotation(DbField.class); String fieldName = annotation.fieldName(); if(fieldName.equals(DEFAULT_FIELD_NAME)) { fieldName = f.getName(); //获取字段名 } int index = cursor.getColumnIndex(fieldName); //字段名转为字段索引 Class<?> fieldClass = f.getType(); //根据成员变量的类型,将从表中读取的数据转换 if(fieldClass == Integer.class || fieldClass == int.class) { f.setInt(sg, cursor.getInt(index)); }else if(fieldClass == Long.class || fieldClass == long.class) { f.setLong(sg, cursor.getLong(index)); }else if(fieldClass == String.class ) { f.set(sg, cursor.getString(index)); }else if(fieldClass == Boolean.class || fieldClass == boolean.class) { f.setBoolean(sg, Boolean.valueOf(cursor.getString(index))); } } } return sg; }
基本的原理框架就如上所述,如果要扩充自定义类型的支持,那么修改写数据以及读取数据代码增加支持即可。
为了提高效率,可以用Hashmap将类信息、字段名和字段索引对应关系等信息缓冲,这样不必每次都通过反射获取。
- DbHelper.zip (13.9 KB)
- 下载次数: 57
评论
2 楼
mypyg
2011-12-22
clazz.getAnnotation(Annotation类)
1 楼
Chansh
2011-12-21
请问如果annotation标记在类上面的,应该怎么获取呢?
发表评论
-
使用googleapi-client-java操作gtasks(二)
2012-03-29 15:34 4591对于很多第三方的机器没有安装Google账户管理,要访问GTa ... -
Android Activity 生命周期再验证
2011-11-22 16:20 7994Android Activity 生命活动 ... -
Nexus one开关键坏掉后的解决方法
2011-10-14 15:17 4476Nexus one手机无法开机了,网上搜索了一下发现很多人遇到 ... -
改包名导致JNI调用失败的问题
2011-08-31 13:41 5150修改以前的代码,移动了一个文件,修改了其包名,在这个文件代码中 ... -
使用googleapi-client-java操作gtasks(一)
2011-08-10 18:07 14818Google Tasks的API终于开放 ... -
一个好用的Google api调试网址
2011-08-09 11:00 1823https://code.google.com/apis/ex ... -
Apk文件Hack试验
2011-07-11 17:54 2862试验1:反编译dex文 ... -
一个由onKeyUp引起的问题
2011-04-19 16:05 1928刚写一个小程序,在用户按下Back按键返回时,需要保存一些数据 ... -
Android自定义组合控件
2011-03-20 18:56 12826目标:实现textview和ImageButton组合,可以通 ... -
也谈Android下一个apk安装多个程序入口图标
2011-03-18 11:28 9197Android中有的Ap功能比较复杂,为了方便用户使用,可以提 ... -
Android AppWidget实例验证
2011-02-25 15:26 133241.创建AppWidget布局,包含两个TextView用来显 ... -
Android Activity LaunchMode 验证
2011-02-23 15:04 8266在Android中,每个Activity有4种LaunchMo ... -
文件夹权限引起的MediaPlayer播放不正常
2011-01-20 20:41 2306写了一个Ap,在程序运行时会解压一些声音文件到/data/da ... -
关于使用InputStreamReader读取GBK编码文件乱码的问题
2011-01-19 17:13 25753BufferedReader reader = new Buf ... -
Android下Listview的onItemClick以及onItemLongClick等易模糊问题验证
2010-12-23 21:10 22767最近在使用Listview又遇到了以前碰到的问题,当Listv ... -
Android PreferenceActivity 学习笔记
2010-12-11 12:45 20029在Ap中有时需要设置一些配置参数,这些参数通过配置文件保存。 ... -
Android平台sqlite快速入门
2010-12-07 12:00 2341以下概念都是在Android平台的sqlite3限制下的理解: ... -
Android下使用googleapi-client-java操作google calendar(三)
2010-11-29 18:57 47724.获取日历列表并显示: 原理:向https://www. ... -
Android下使用googleapi-client-java操作google calendar(二)
2010-11-28 22:50 23573.与服务器进行数据交互: 交互是通过HTTP请求及响应来进 ... -
Android下使用googleapi-client-java操作google calendar(一)
2010-11-19 14:41 4974刷机又把数据刷没了,网络时代,数据还是和服务器同步好了。 从 ...
相关推荐
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
3.2.3 Java反射机制 3.3 资源访问利器 3.3.1 资源抽象接口 3.3.2 资源加载 3.4 BeanFactory和ApplicationContext 3.4.1 BeanFactory介绍 3.4.2 ApplicationContext介绍 3.4.3 父子容器 3.5 Bean的生命周期 3.5.1 ...
3.2.3 Java反射机制 3.3 资源访问利器 3.3.1 资源抽象接口 3.3.2 资源加载 3.4 BeanFactory和ApplicationContext 3.4.1 BeanFactory介绍 3.4.2 ApplicationContext介绍 3.4.3 父子容器 3.5 Bean的生命周期 3.5.1 ...