目录
前言
android发展至今开源框架很多,数据库框架也有一些比较好的,而对于我们开发者而言网上有很多框架,我们只需要拿过来会用,一般都可以解决项目中遇到的问题,而我们自己写的代码量就比较少了,也很难突破开发瓶颈,开发模式变成了Ctrl+C Ctrl+V,而依赖过来的jar包,有些未必是项目需要用到的,很多冗余代码量较大的时候,间接的导致app变大,所以这个时候就需要我们手写代码来解决这一问题,今天写一下数据库框架。
正文部分
1.首先新建一个AS项目工程,建立一个顶层数据库接口IBaseDao 这里定义一些需要用的方法,最基础的增删改查之类的,让实现类去调用,insert方法是需要插入的对象,当然我们需要插入的对象应该是由用户去决定,所以这里用范型,用户传入插入对象即可
public interface IBaseDao<T>{
/** 插入操作 */
long insert(T entity);
/** 删除操作 */
int delete(String condition,String[] value);
}
2.再建立一个实现类去实现上面定义的接口,而我们需要操作数据库,这里就会用到android提供的一个数据库操作类
SQLiteDatabase是必不可少的,在框架层操作外层对象的方法用 Class<T> 获取当前的字节码 然后建立一个表名 设置缓存,在初始化方法里建立表,那我们如何去获取到表得名字呢,可以通过java的反射机制,首先建立一个对象,例如User用户信息,User类(这里跳到User代码继续阅读,然后再返回到当前位置)
回到这里时候,已经解决了获取到表名和对象字段的方法,建立表的具体代码逻辑可断点一步步看下去
public class BaseDao<T> implements IBaseDao<T>{
//操作数据库,持有数据库操作的引用
private SQLiteDatabase sqLiteDatabase;
//持有操作数据库所对应的java类型
private Class<T> entityClass;
//表名
private String tableName;
//标记,用来是否已经存在
private boolean isInit = false;
//定义一个缓存空间(key - 字段名 )
private HashMap<String,Field> cacheMap;
public boolean init(SQLiteDatabase sqLiteDatabase, Class<T> entityClass) {
this.sqLiteDatabase = sqLiteDatabase;
this.entityClass = entityClass;
//自动建表(只需要建一次)
if (!isInit){
//如果没有建过表就建一张新表
tableName=entityClass.getAnnotation(DBTable.class).value();
if (!sqLiteDatabase.isOpen()){
return false;
}
//执行自动建表的动作
String creatTableSql = getCreateTableSql();
sqLiteDatabase.execSQL(creatTableSql);
isInit = true;
//初始化缓存空间
cacheMap = new HashMap<>();
initCacheMap();
}
return isInit;
}
private void initCacheMap() {
//1.取到所有得列表
String sql = "select * from " + tableName +" limit 1,0";
Cursor cursor = sqLiteDatabase.rawQuery(sql,null);
String[] columnNames = cursor.getColumnNames();
//2.取所有得成员变量
Field[] clounmnFields = entityClass.getDeclaredFields();
//3.通过2层循环让他们对应起来
for (String columnName: columnNames){
Field resultField = null;
for (Field field:clounmnFields){
String fieldAnnotionName = field.getAnnotation(DBField.class).value();
if (columnName.equals(fieldAnnotionName)){
resultField = field;
break;
}
}
if (resultField != null){
cacheMap.put(columnName,resultField);
}
}
}
/***
* 自动创建表
* @return
*/
private String getCreateTableSql() {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("create table if not exists ");
stringBuffer.append(tableName+"(");
//反射得到所有的成员变量
Field[] fields = entityClass.getDeclaredFields();
for (Field field: fields){
Class type = field.getType();
if (type == String.class){
stringBuffer.append(field.getAnnotation(DBField.class).value()+" TEXT,");
}else if (type == Integer.class){
stringBuffer.append(field.getAnnotation(DBField.class).value()+" INTEGER,");
}else if (type == Long.class){
stringBuffer.append(field.getAnnotation(DBField.class).value()+" BIGINT,");
}else if (type == Double.class){
stringBuffer.append(field.getAnnotation(DBField.class).value()+" DOUBLE,");
}else if (type == byte[].class){
stringBuffer.append(field.getAnnotation(DBField.class).value()+" BLOB,");
}else {
continue;
}
}
if (stringBuffer.charAt(stringBuffer.length() - 1) == ','){
stringBuffer.deleteCharAt(stringBuffer.length() - 1);
}
stringBuffer.append(")");
return stringBuffer.toString();
}
/**
*
* @param entity
* @return
*/
@Override
public long insert(T entity) {
//1.准备好ContentValues
Map<String,String> map = getValues(entity);
//2.插入内容
ContentValues values = getContentValues(map);
//3.执行插入
long result = sqLiteDatabase.insert(tableName,null,values);
return result;
}
/**
* 删除操作
* @param condition
* @return
*/
@Override
public int delete(String condition,String[] value) {
sqLiteDatabase.delete(tableName,condition,value);
return 0;
}
private ContentValues getContentValues(Map<String, String> map) {
ContentValues contentValues = new ContentValues();
Set keys = map.keySet();
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()){
String key = iterator.next();
String value = map.get(key);
if (value != null){
contentValues.put(key,value);
}
}
return contentValues;
}
private Map<String,String> getValues(T entity) {
HashMap<String,String> map = new HashMap<>();
Iterator<Field> fieldItertor = cacheMap.values().iterator();
while (fieldItertor.hasNext()){
Field field = fieldItertor.next();
field.setAccessible(true);
//获取变量的值
try {
Object object = field.get(entity);
if (object == null){
continue;
}
String value = object.toString();
//获取别名 _id name password
String key = field.getAnnotation(DBField.class).value();
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)){
map.put(key,value);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return map;
}
}
这里是User对象,大家会发现这里有个@DBTable,而这个是用来反射表名使用的,如下所示,@Target是注解代表标示的位置,参数有很多,可以对应使用,这里把他写在类上的,所以使用ElementType.TYPE,第二个再设置它的保留时间,@Retention,这里选择的是RetentionPolicy.RUNTIME,表示运行时,通过DBTable反射机制可以得到表名,而我们需要获取对象信息里所有字段的话,也需要同样方式,这里就继续建立一个DBField,这些工作做完之后,返回上面继续BaseDao类代码
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBField {
String value();
}
@DBTable("tb_user")
public class User {
@DBField("id")
private Integer id;
@DBField("name")
private String name;
@DBField("password")
private String password;
public User(Integer id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
String value();
}
DBField
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBField {
String value();
}
最终的调用方式:
BaseDao<User> userDao = BaseDaoFactoty.getOurInstance().getBaseDao(User.class);
userDao.insert(new User(1,".","hahaha"));
demo 地址如下:https://github.com/w947329887/- |