您的位置:首页 > 移动开发 > Android开发

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 {

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语句来实现。不过要大家再次完美一下,实现相应的接口而已。抛砖引玉,希望大家指导。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: