- 浏览: 549415 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
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 4635对于很多第三方的机器没有安装Google账户管理,要访问GTa ... -
Android Activity 生命周期再验证
2011-11-22 16:20 8032Android Activity 生命活动 ... -
Nexus one开关键坏掉后的解决方法
2011-10-14 15:17 4504Nexus one手机无法开机了,网上搜索了一下发现很多人遇到 ... -
改包名导致JNI调用失败的问题
2011-08-31 13:41 5201修改以前的代码,移动了一个文件,修改了其包名,在这个文件代码中 ... -
使用googleapi-client-java操作gtasks(一)
2011-08-10 18:07 14931Google Tasks的API终于开放 ... -
一个好用的Google api调试网址
2011-08-09 11:00 1852https://code.google.com/apis/ex ... -
Apk文件Hack试验
2011-07-11 17:54 2894试验1:反编译dex文 ... -
一个由onKeyUp引起的问题
2011-04-19 16:05 1970刚写一个小程序,在用户按下Back按键返回时,需要保存一些数据 ... -
Android自定义组合控件
2011-03-20 18:56 12901目标:实现textview和ImageButton组合,可以通 ... -
也谈Android下一个apk安装多个程序入口图标
2011-03-18 11:28 9234Android中有的Ap功能比较复杂,为了方便用户使用,可以提 ... -
Android AppWidget实例验证
2011-02-25 15:26 134071.创建AppWidget布局,包含两个TextView用来显 ... -
Android Activity LaunchMode 验证
2011-02-23 15:04 8358在Android中,每个Activity有4种LaunchMo ... -
文件夹权限引起的MediaPlayer播放不正常
2011-01-20 20:41 2364写了一个Ap,在程序运行时会解压一些声音文件到/data/da ... -
关于使用InputStreamReader读取GBK编码文件乱码的问题
2011-01-19 17:13 25812BufferedReader reader = new Buf ... -
Android下Listview的onItemClick以及onItemLongClick等易模糊问题验证
2010-12-23 21:10 22808最近在使用Listview又遇到了以前碰到的问题,当Listv ... -
Android PreferenceActivity 学习笔记
2010-12-11 12:45 20073在Ap中有时需要设置一些配置参数,这些参数通过配置文件保存。 ... -
Android平台sqlite快速入门
2010-12-07 12:00 2385以下概念都是在Android平台的sqlite3限制下的理解: ... -
Android下使用googleapi-client-java操作google calendar(三)
2010-11-29 18:57 48044.获取日历列表并显示: 原理:向https://www. ... -
Android下使用googleapi-client-java操作google calendar(二)
2010-11-28 22:50 23863.与服务器进行数据交互: 交互是通过HTTP请求及响应来进 ... -
Android下使用googleapi-client-java操作google calendar(一)
2010-11-19 14:41 5010刷机又把数据刷没了,网络时代,数据还是和服务器同步好了。 从 ...
相关推荐
文件`annotation_orm`可能包含了实现这些功能的核心代码,如注解定义、反射处理逻辑以及JDBC操作的封装。通过学习这个案例,开发者可以深入理解如何在实际项目中有效利用Java的注解和反射机制,提升代码质量和可维护...
在Java编程中,反射、注解(Annotation)和泛型是三个非常重要的特性,它们各自在不同的场景下发挥着关键作用。这篇博文“利用java反射、注解及泛型模拟ORM实现”旨在探讨如何结合这三种技术来实现对象关系映射(ORM...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
本主题将深入探讨如何利用Java的注解(Annotation)和反射(Reflection)技术来构建一个自定义的数据库框架。通过这种方式,开发者不仅可以更好地理解这些核心Java特性,还能提升开发效率。 注解是Java提供的一种元编程...
Java通用API工具合集是Java开发者的重要参考资料,它包含了Java平台标准版(Java SE)的各种类库和接口的详尽文档。这个最全中文版使得中国开发者能够更方便地理解和使用Java API,避免了语言障碍,提高了开发效率。...
在Java编程语言中,注解(Annotation)和反射(Reflection)是两个强大的工具,它们极大地扩展了代码的灵活性和动态性。这篇学习笔记将深入探讨这两个主题,帮助开发者更好地理解和运用它们。 首先,我们来了解注解...
Java反射是Java编程语言中的一个强大特性,它允许运行时的程序访问并操作类、接口、字段和方法的信息,即使这些信息在编译时未知。这个特性使得Java具有很高的灵活性和动态性,尤其是在处理元数据、插件系统、以及...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
其特性包括跨平台性(通过Java虚拟机JVM运行在不同操作系统上)、安全性(内置安全机制防止恶意代码)、可移植性(一次编写,到处运行)、高性能(JIT编译器优化)、简单易学(C/C++语法的简化版本)以及面向对象...
Java Database Connectivity (JDBC) 是Java访问数据库的标准API,可以用来连接各种类型的数据库,执行SQL语句,处理结果集等。它提供了连接池、事务管理等功能,方便进行数据库操作。 【反射】 Java反射机制允许在...
7. **反射机制**:Java反射允许在运行时检查类的信息,动态创建对象和调用方法,这对于编写通用性强的代码非常有用。 8. **JDBC数据库访问**:Java Database Connectivity (JDBC) 是Java访问数据库的标准API,包括...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
4. **异常处理**:Java的异常处理机制通过try-catch-finally语句块实现,有助于程序的健壮性。了解不同类型的异常(检查型和运行时异常)以及如何自定义异常是非常重要的。 5. **多线程**:Java内置了对多线程的...
6. **数据库连接**:JDBC(Java Database Connectivity)是Java访问数据库的标准API,通过`DriverManager`、`Connection`、`Statement`和`ResultSet`等类,可以实现数据库的连接、查询、插入、更新和删除操作。...
Java的知识体系非常广泛,包括基础语法、类与对象、封装、继承、多态、接口、异常处理、集合框架、IO流、多线程、网络编程、数据库操作、反射机制、注解、模块化、JVM优化等多个方面。 1. 基础语法:Java的基础语法...
java.sql 提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。 java.text 提供以与自然语言无关的方式来处理文本、日期、数字和消息的类和接口。 java.text.spi java.text ...
- **多态**:同一接口下不同对象表现出不同的行为,是Java中实现动态绑定的关键。 - **抽象类与接口**:抽象类用于定义通用行为,接口则强制实现特定方法。 **4. 内存管理** - **垃圾回收**:Java自动管理内存,...