Android应用开发技巧之更方便的使用Sqlite
2015-08-13 09:17
666 查看
做应用的大多离不开数据库的支持,但是就是这么常用的对象,你有没有想过让他更方便的使用呢?什么是更方便,我的定义就是不用在每次需要用它的时候对SQL语句做过多的关心,我们应该更多的关心每一个字段的含义;也就是我们应用开发更多的关心应该在业务上,而不是在SQL语句的拼接中。
因此本人要带领大家从0到1到开始一步步优化SQLite的使用。
整体思路如下:
首先,对于SQL语句,我们发现他是不是很有规律,因此在SQL的拼接上完全可以实现部分自动化;
其次,我们应该直接将数据库字段实体类和数据库的建表,查询等关联起来;这样,我们才能最大化的达到资源的复用。
因此我结合Java的相关知识设计如下:
首先,我们必须继承SQLiteOpenHelper来实现一个建库建表的基类;
代码如下:
/**
* @author 徐晔
* @note 数据库操作类
*/
@SuppressWarnings(“rawtypes”)
public class XYDBhelper extends SQLiteOpenHelper {
}
我将里面的建表语句利用反射机制实现,将建表语句的实现延迟实现,为我们下一步做一个准备。
再看看这里面牵扯到的两个类:
/**
*
* @author 徐晔 需要建表实现的接口
*/
abstract public class XYCreatMethod {
/* 获取建立表格的SQL语句 /
abstract public String getcreattablesql();
}
/**
*
* @author xuye
* @not 版本号变化时需要实现的接口方法
*/
public interface XYversionchange {
/* 版本升级时 /
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion);
}
这两个一个是建表语句需要继承的基类,一个是版本发生升级或者降级需要执行的方法。
在此我们可以直接将所有需要建立表格的语句继承XYCreatMethod类实现,这里就是一个灵活的地方,我们可以按照传统的实现方法,也可以自己在getcreattablesql()方法里面玩一些猫腻;
如果要将字段实体类和建表结合起来,那么可以利用注解的特点结合反射的特点来实现,我的实现如下:
首先自定义一个类的注解类:
@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取
@Target(ElementType.TYPE)//目标是接口、类、枚举、注解
@Documented//文档生成时,该注解将被包
public @interface XYTable {
}
在定义一个字段的注解类:
然后是将带有注解的字段表和字段和建表语句结合起来的方法:
/**
* @author 徐晔
* 利用反射机制进行建立表操作
*/
public class XYBaseCreatMethod extends XYCreatMethod {
}
下面举一个字段实体类的例子:
然后该实现查询的相关方法了;主要是根据字段类进行查询。
/**
* @author 徐晔
* @note 数据库操作方法的实现
*/
public class XYDBmanage {
}
,好了,大家按照这个思路完这些代码,后面使用数据库就会变得很简单。并且这一套实现思路不仅仅是只可以用反射实现,对于复杂的业务也支持自己写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) { // 如果属性的值不为空则存入values if (!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 studio f3怎么不跳转?
- Android源码——小苏闹钟
- onSaveInstanceState和onRestoreInstanceState触发的时机
- Android RecyclerView的StaggeredGridLayoutManager和CardView
- 百度地图(Android)多地图重叠bug记录
- android ORM数据库框架ActiveAndroid的简单使用
- Android读取assets中文件
- android bind service总结
- 根据mac地址+deviceid获取设备唯一编码 获取手机及SIM卡相关信息
- Android常用工具方法(关闭软键盘,安装apk,检测程序是否安装...)
- Android之如何自定义ListView样式
- Android之如何给ListView添加过滤器
- Android之如何使用ListView列表视图
- Android测试中被测应用挂了怎么办?
- Android测试中被测应用挂了怎么办?
- Android测试中被测应用挂了怎么办?
- 'register_android_system_OsConstants(_JNIEnv*)'解决方案
- android service绑定
- Android Api Demos登顶之路(三十二)Alarm Service
- 简单粗暴实现RecycleView的瀑布流的粘性头部(非ItemDecoration实现)