Android应用开发技巧之更方便的使用Sqlite
做应用的大多离不开数据库的支持,但是就是这么常用的对象,你有没有想过让他更方便的使用呢?什么是更方便,我的定义就是不用在每次需要用它的时候对SQL语句做过多的关心,我们应该更多的关心每一个字段的含义;也就是我们应用开发更多的关心应该在业务上,而不是在SQL语句的拼接中。
因此本人要带领大家从0到1到开始一步步优化SQLite的使用。
整体思路如下:
首先,对于SQL语句,我们发现他是不是很有规律,因此在SQL的拼接上完全可以实现部分自动化;
其次,我们应该直接将数据库字段实体类和数据库的建表,查询等关联起来;这样,我们才能最大化的达到资源的复用。
因此我结合Java的相关知识设计如下:
首先,我们必须继承SQLiteOpenHelper来实现一个建库建表的基类;
代码如下:
/**
* @author 徐晔
* @note 数据库操作类
*/
@SuppressWarnings(“rawtypes”)
public class XYDBhelper extends SQLiteOpenHelper {
private List<Class<? extends XYCreatMethod>> clslist = new ArrayList<Class<? extends XYCreatMethod>>();
private XYversionchange xYversionchange;public XYDBhelper(Context context, String name, CursorFactory factory,int version) {super(context, name, factory, version);
}public void setXYversionchange(XYversionchange xYversionchange) {this.xYversionchange = xYversionchange;
}/*** 添加想要建表的类* * @param cMethord*/
public void addCreatMethord(Class<? extends XYCreatMethod> cls) {if (cls != null) {clslist.add(cls);}
}@Override
public void onCreate(SQLiteDatabase db) {// 利用反射机制来建立表格db.beginTransaction();try {for (Class<? extends XYCreatMethod> cls : clslist) {Constructor[] constructors = cls.getDeclaredConstructors();AccessibleObject.setAccessible(constructors, true);for (Constructor con : constructors) {if (con.isAccessible()) {Object classObject = con.newInstance();Method method = cls.getMethod(XYCreatMethod.CREATTABLEMETHORD_NAME);String creatsql = (String) method.invoke(classObject);db.execSQL(creatsql);}}}db.setTransactionSuccessful();} catch (Exception e) {e.printStackTrace();}finally{db.endTransaction();}
}@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {if (xYversionchange != null) {xYversionchange.onUpgrade(db, oldVersion, newVersion);}}@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {if (xYversionchange != null) {xYversionchange.onDowngrade(db, oldVersion, newVersion);}}
}
我将里面的建表语句利用反射机制实现,将建表语句的实现延迟实现,为我们下一步做一个准备。
再看看这里面牵扯到的两个类:
/**
*
* @author 徐晔 需要建表实现的接口
*/
abstract public class XYCreatMethod {
/* 获取建立表格的SQL语句 /
abstract public String getcreattablesql();
/** 建立表格方法名,利于DBhelper进行建立表格操作 */
public final static String CREATTABLEMETHORD_NAME = "getcreattablesql";
}
/**
*
* @author xuye
* @not 版本号变化时需要实现的接口方法
*/
public interface XYversionchange {
/* 版本升级时 /
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
/** 版本降级时 */
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion);
}
这两个一个是建表语句需要继承的基类,一个是版本发生升级或者降级需要执行的方法。
在此我们可以直接将所有需要建立表格的语句继承XYCreatMethod类实现,这里就是一个灵活的地方,我们可以按照传统的实现方法,也可以自己在getcreattablesql()方法里面玩一些猫腻;
如果要将字段实体类和建表结合起来,那么可以利用注解的特点结合反射的特点来实现,我的实现如下:
首先自定义一个类的注解类:
@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取
@Target(ElementType.TYPE)//目标是接口、类、枚举、注解
@Documented//文档生成时,该注解将被包
public @interface XYTable {
/**表名字*/
public String tablename() default "className";
/** 唯一约束,指定某列和几列组合的数据不能重复 */
public String[] unique() default "";
/**主键约束,指定某列的数据不能重复、唯*/
public String primary_key() default "id";
/**主键的类型*/
public String primary_key_type() default "integer";
/**主键是否自增*/
public boolean is_auto_increase_primarykey() default false;
/**主键是否非空*/
public boolean primary_notnull() default true;/**外键,指定该列记录属于主表中的一条记录,参照另一条数据 */
public String foreign_key() default "";
/**检查,指定一个表达式,用于检验指定数据 */
public String check() default "";
}
在定义一个字段的注解类:
@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取
@Target(ElementType.FIELD)//目标是字段
@Documented//文档生成时,该注解将被包
public @interface XYTableField {/**是什么类型的字段 */public String Type() default "varchar";/**非空约束 */public boolean not_null() default false;
}
然后是将带有注解的字段表和字段和建表语句结合起来的方法:
/**
* @author 徐晔
* 利用反射机制进行建立表操作
*/
public class XYBaseCreatMethod extends XYCreatMethod {
private Class<?> cls;
public XYBaseCreatMethod(Class<?> cls){this.cls=cls;
}@Override
public String getcreattablesql() {try {return getcreattablesql(cls);} catch (Exception e) {e.printStackTrace();return "";}
}/*** 获取建表SQL* @param cls* @return* @throws NullPointerException*/
public String getcreattablesql(Class<?> cls) throws NullPointerException{StringBuilder mBuilder = new StringBuilder();XYTable table = cls.getAnnotation(XYTable.class);if (table == null || table.tablename() == null) {throw new NullPointerException("没有添加应该有的数据库注释");}mBuilder.append("create table " + table.tablename());mBuilder.append("(" + table.primary_key() + " "+ table.primary_key_type() + " primary key");if (table.is_auto_increase_primarykey()) {mBuilder.append(" autoincrement");}if(table.primary_notnull()){mBuilder.append(" not null");}mBuilder.append(",");for (Field field : cls.getFields()) {XYTableField mField = field.getAnnotation(XYTableField.class);if (mField == null || mField.Type() == null|| mField.Type().length() == 0) {continue;}String name = field.getName();mBuilder.append(name);mBuilder.append(" " + mField.Type());if(mField.not_null()){mBuilder.append(" not null");}mBuilder.append(",");}if (table.unique() == null || table.unique().length == 0) {mBuilder.deleteCharAt(mBuilder.length() - 1);} else {mBuilder.append("unique(");for (String fie : table.unique()) {mBuilder.append(fie + ",");}mBuilder.deleteCharAt(mBuilder.length() - 1);mBuilder.append(")");}mBuilder.append(")");return mBuilder.toString();}
}
下面举一个字段实体类的例子:
/*** @author 徐晔*/
@XYTable(tablename = "DownloadHsitory", primary_key = "id", foreign_key = "", unique = { "url" }, is_auto_increase_primarykey = true, primary_notnull = true)
public class DownloadHsitory {/*** 下载地址* * @note* */@XYTableField(Type = "varchar", not_null = true)public String url;/*** 下载文件存储的绝对路径* * @note* */@XYTableField(Type = "varchar", not_null = true)public String savepath;/*** 已经下载的文件大小* * @note* */@XYTableField(Type = "integer", not_null = true)public long downlength;/*** 整个文件的大小* * @note* */@XYTableField(Type = "integer", not_null = true)public long totallength;
}
然后该实现查询的相关方法了;主要是根据字段类进行查询。
/**
* @author 徐晔
* @note 数据库操作方法的实现
*/
public class XYDBmanage {
public XYDBhelper dBhelper;
private SQLiteDatabase database;
private Context context;
private int version;
private String dbname;
private CursorFactory factory;private static XYDBmanage xydBmanage = null;public static XYDBmanage getInstance(Context context, String name,CursorFactory factory, int version) {if (xydBmanage == null) {synchronized (XYDBmanage.class) {if (xydBmanage == null) {xydBmanage = new XYDBmanage(context, name, factory, version);}}}return xydBmanage;
}private XYDBmanage(Context context, String name, CursorFactory factory,int version) {this.context = context;this.version = version;this.dbname = name;this.factory = factory;
}/*** 打开数据库*/
private void openDB() {if (dBhelper == null) {dBhelper = new XYDBhelper(context, dbname, factory, version);}if (database == null) {database = dBhelper.getWritableDatabase();}
}/*** 关闭数据库*/
private void closeDB() {if (database.isOpen()) {database.close();database.releaseReference();database = null;}
}/*** 根据Class获取表名字*/
private String getTablename(Class<?> cls) {String tablename = "";XYTable mani = cls.getAnnotation(XYTable.class);if (mani == null) {return null;}tablename = mani.tablename();return tablename;
}/*** 查询数据*/
public synchronized List<?> getObjects(String columeName, String where,String order, Class<?> cls) throws Exception {String tablename = getTablename(cls);if (tablename == null || columeName == null) {return null;}List<Object> mList = new ArrayList<Object>();Object obj = null;StringBuilder mBuilder = new StringBuilder();mBuilder.append("select " + columeName + " from " + tablename);if (where != null) {mBuilder.append(" where " + where);}if (order != null) {mBuilder.append(" order by" + order);}openDB();Cursor mCursor = database.rawQuery(mBuilder.toString(), null);Field[] fields = cls.getFields();if (mCursor != null) {while (mCursor.moveToNext()) {obj = cls.newInstance();for (Field field : fields) {try {setValue(obj, field, mCursor.getString(mCursor.getColumnIndex(field.getName())));} catch (Exception e) {e.printStackTrace();}}mList.add(obj);}}if (!mCursor.isClosed()) {mCursor.close();}closeDB();return mList;
}/*** 插入数据库*/
public synchronized void insert(List<?> liss, Class<?> cls)throws Exception {ContentValues values = null;String tablename = getTablename(cls);openDB();for (Object temp : liss) {Field[] fields = cls.getFields();values = new ContentValues();for (Field field : fields) {if (temp.getClass().getField(field.getName()).get(temp) != null) {values.put(field.getName(),temp.getClass().getField(field.getName()).get(temp).toString());}}Log.v("values", values + "");database.insert(tablename, null, values);}closeDB();
}/*** 使用事物插入数据库*/
public synchronized void insertwithTransaction(List<?> liss, Class<?> cls)throws Exception {ContentValues values = null;String tablename = getTablename(cls);openDB();database.beginTransaction();for (Object temp : liss) {Field[] fields = cls.getFields();values = new ContentValues();for (Field field : fields) {if (temp.getClass().getField(field.getName()).get(temp) != null) {values.put(field.getName(),temp.getClass().getField(field.getName()).get(temp).toString());}}Log.v("values", values + "");database.insert(tablename, null, values);}database.setTransactionSuccessful();database.endTransaction();closeDB();
}/*** 更新数据库*/
public synchronized void updateState(Object obj, String where, Class<?> cls)throws Exception {StringBuilder SQL = new StringBuilder(" update ");StringBuilder value = new StringBuilder();String tablename = getTablename(cls);SQL.append(tablename);SQL.append(" set ");// 获得obj的所有属性Field[] fields = obj.getClass().getFields();for (Field field : fields) {// 如果属性的值不为空则存入valuesif (!field.getName().equals(tablename)) {if (null != field.get(obj)) {value.append(field.getName() + " = '"+ String.valueOf(field.get(obj) + "' ,"));}}}if (value.length() <= 0) {return;}value.delete(value.length() - 1, value.length());SQL.append(value);if (where != null && where.length() > 0) {SQL.append(" where " + where);}openDB();Log.v("updateState SQL=>", SQL.toString());database.execSQL(SQL.toString());clone();
}/*** 删除数据库中指定的记录* * @param listObj* @throws Exception*/
public synchronized void delete(String where, Class<?> cls)throws Exception {String tablename = getTablename(cls);String sql = "delete from " + tablename;if (where != null && !where.equals("")) {sql = sql + " where " + where;}Log.v("sql=>", sql);openDB();database.execSQL(sql);closeDB();
}/*** 执行自己的sql*/
public synchronized void execSQL(String SQL) {// 获取数据库操作openDB();database = dBhelper.getWritableDatabase();database.execSQL(SQL);Log.v("sql=>", SQL);closeDB();
}/*** 给obj对象的field属性赋值* * @param obj* 对象* @param field* 属性* @param value* 值*/
public void setValue(Object obj, Field field, String value) {try {// 获得field属性的类型名String class_type = field.getType().getName();// 将value转换成和属性类型一样的数据类型if (class_type.equals(String.class.getName())) {field.set(obj, value);} else if (class_type.equals("int")|| class_type.equals(Integer.class.getName())) {field.set(obj, Integer.parseInt(value));} else if (class_type.equals("double")|| class_type.equals(Double.class.getName())) {field.set(obj, Double.parseDouble(value));} else if (class_type.equals("boolean")|| class_type.equals(Boolean.class.getName())) {field.set(obj, Boolean.parseBoolean(value));} else if (class_type.equals("float")|| class_type.equals(Float.class.getName())) {field.set(obj, Float.parseFloat(value));} else if (class_type.equals("short")|| class_type.equals(Short.class.getName())) {field.set(obj, Short.parseShort(value));} else if (class_type.equals("long")|| class_type.equals(Long.class.getName())) {field.set(obj, Integer.parseInt(value));} else if (class_type.equals("char")|| class_type.equals(Character.class.getName())) {field.set(obj, value);} else if (class_type.equals("byte")|| class_type.equals(Byte.class.getName())) {field.set(obj, Byte.parseByte(value));}} catch (Exception e) {e.printStackTrace();}
}
}
,好了,大家按照这个思路完这些代码,后面使用数据库就会变得很简单。并且这一套实现思路不仅仅是只可以用反射实现,对于复杂的业务也支持自己写SQL语句来实现。不过要大家再次完美一下,实现相应的接口而已。抛砖引玉,希望大家指导。
Android应用开发技巧之更方便的使用Sqlite相关推荐
- Android高效开发技巧:代码判空、逻辑判断语句
文章目录 前言 一.判空 二.判断变量边界 1.if 2.while 3.for 总结 前言 在Android Studio中书写逻辑判断语句,如果一行一行自己进行书写,难免在速度上会落后别人,本文就 ...
- 从Android界面开发谈起(转)
原文地址:http://blog.csdn.net/nieweilin/article/details/5967815 这篇文章没有打算有一个很好的逻辑去介绍android的某个方面,全盘大致上就是我 ...
- 从Android界面开发谈起
这篇文章没有打算有一个很好的逻辑去介绍android的某个方面,全盘大致上就是我接触.了解android的ui开发后到现在的一些感想以及个人理解吧! 全文可能会涉及到java.android开发.an ...
- Android NFC 开发实例
http://blog.csdn.net/pku_android/article/details/7430788 类: Android应用开发系列教程 Android应用开发技巧2012-04-06 ...
- Android JNI开发入门之二
在上一篇文章<Android JNI开发入门之一>中,我介绍了Android应用程序(APK)怎样通过JNI调用Native C实现的共享库.本文将进一步介绍Android应用程序通过JN ...
- 一眼就看懂;Android App 开发前景介绍及学习路线规划
Android App 开发的发展趋势和前景 安卓 App 开发是大趋势 从目前的各大社交终端以及移动媒体中手机占了百分之75.5的比例,随着各种移动端的系统升级,手机 App 也在现今这个社会面临着 ...
- 学Android移动开发 第1章 Android基础入门
文章目录 1.1 Android简介 什么是Android Android和iOS主要区别 1.1.1 通信技术 1.1.2 Android起源 1.1.3 Android体系结构 1.1.4 Dal ...
- Android开发技巧——自定义控件之自定义属性
Android开发技巧--自定义控件之自定义属性 掌握自定义控件是很重要的,因为通过自定义控件,能够:解决UI问题,优化布局性能,简化布局代码. 上一篇讲了如何通过xml把几个控件组织起来,并继承某个 ...
- 解密android日志xlog,安卓开发技巧2:自定义日志工具类XLog的实现
安卓开发技巧二:自定义日志工具类XLog的实现 我们在开发过程中,打印日志是必不可少的一个调试环节,然而,直接使用系统自带的Log日志类,并不能满足我们实际项目的需求:假如我们现在在开发一款比较大的项 ...
最新文章
- 压缩人工智能的数据值
- Bicolor软件 中 GATB
- 没有任何基础的可以学python吗-对没有编程基础的人来说,直接学Python入门IT合适吗?...
- c++编辑器_盘点四款PDF编辑器,使用它们,编辑PDF文件没问题!
- QT的QBrush类的使用
- Surface Pro 4 和 Surface Book 使用名为 Surface UEFI(统一可扩展固件接口)的新固件接口...
- java修车_JAVA小练习34——使用java描述一个车类与一个修车厂类
- max 宏定义取消:error C2589: error C2059: 语法错误 : “::”
- 深度学习- 激活函数总结(Sigmoid, Tanh, Relu, leaky Relu, PReLU, Maxout, ELU, Softmax,交叉熵函数)
- oracle_jdbc新建实例,JDBC的操作步骤和实例
- 今天为你分享互联网营销的两个核心思维
- LOCK - 明确地锁定一个表
- oracle数据库赋权_Oracle角色权限创建用户赋权
- X Lossless Decoder for mac(XLD音频无损解码器)
- java applet怎么传参,使用不带浏览器的参数运行java applet
- 输入需求自动生成代码,这个AI有点厉害,可以替代真人吗?
- 提高睡眠质量的东西,每天晚上睡不着的你一定要试试
- odd在c语言中的意思,odd是什么意思
- 服务器打印后台程序没有响应,Win10提示打印后台处理程序服务没有运行如何解决...
- 万变不离其宗之反射原理篇