首先IDaoSupport接口,有查询,插入单条数据,批量插入,删除,更新
public interface IDaoSupport<T> {
void init(SQLiteDatabase sqLiteDatabase, Class<T> clazz);
// 插入数据
public long insert(T t);
// 批量插入 检测性能
public void insert(List<T> datas);
// 获取专门查询的支持类
QuerySupport<T> querySupport();
// 按照语句查询
int delete(String whereClause, String... whereArgs);
int update(T obj, String whereClause, String... whereArgs);
}
DaoSupportFactory:工厂模式:单列模式获得实例,并能够创建数据库或者打开数据库openOrCreateDatabase,并持有外部数据库的引用,因为是直接MainActivity去调用
public class DaoSupportFactory {
private static DaoSupportFactory mFactory;
//单例模式
public static DaoSupportFactory getFactory() {
if (mFactory == null) {
synchronized (DaoSupportFactory.class) {
if (mFactory == null) {
mFactory = new DaoSupportFactory();
}
}
}
return mFactory;
}
// 持有外部数据库的引用
private SQLiteDatabase mSqLiteDatabase;
private DaoSupportFactory() {
// 把数据库放到内存卡里面 判断是否有存储卡 6.0要动态申请权限
File dbRoot = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator + "nhdz" + File.separator + "database");
if (!dbRoot.exists()) {
dbRoot.mkdirs();
}
File dbFile = new File(dbRoot, "nhdz.db");
// 打开或者创建一个数据库
mSqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(dbFile, null);
}
public <T> IDaoSupport<T> getDao(Class<T> clazz) {
IDaoSupport<T> daoSoupport = new DaoSupport();
daoSoupport.init(mSqLiteDatabase, clazz);
return daoSoupport;
}
}
在使用DaoSupport之前先封装一些工具类:①获得类的名字,比如person。②数据库操作的时候根据类型进行转换。③查询数据:cursor.getInt();将int第一个字符进行转换成大写
public class DaoUtil {
private DaoUtil() {
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* 获得类名
*/
public static String getTableName(Class<?> clazz) {
return clazz.getSimpleName();
}
/**
* 数据库操作的时候根据类型进行转换
*/
public static String getColumnType(String type) {
String value = null;
if (type.contains("String")) {
value = " text";
} else if (type.contains("int")) {
value = " integer";
} else if (type.contains("boolean")) {
value = " boolean";
} else if (type.contains("float")) {
value = " float";
} else if (type.contains("double")) {
value = " double";
} else if (type.contains("char")) {
value = " varchar";
} else if (type.contains("long")) {
value = " long";
}
return value;
}
/**
* 查询数据:cursor.getInt();将int第一个字符进行转换成大写
*/
public static String capitalize(String string) {
if (!TextUtils.isEmpty(string)) {
return string.substring(0, 1).toUpperCase(Locale.US) + string.substring(1);
}
return string == null ? null : "";
}
}
DaoSupport:更新,插入,删除等操作
public class DaoSupport<T> implements IDaoSupport<T> {
// SQLiteDatabase
private SQLiteDatabase mSqLiteDatabase;
// 泛型类
private Class<T> mClazz;
private String TAG = "DaoSupport";
private static final Object[] mPutMethodArgs = new Object[2];
private static final Map<String, Method> mPutMethods
= new ArrayMap<>();
public void init(SQLiteDatabase sqLiteDatabase, Class<T> clazz) {
this.mSqLiteDatabase = sqLiteDatabase;
this.mClazz = clazz;
// 创建表
/*"create table if not exists Person ("
+ "id integer primary key autoincrement, "
+ "name text, "
+ "age integer, "
+ "flag boolean)";*/
StringBuffer sb = new StringBuffer();
sb.append("create table if not exists ")
.append(DaoUtil.getTableName(mClazz))
.append("(id integer primary key autoincrement, ");
Field[] fields = mClazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);// 设置权限
String name = field.getName();
String type = field.getType().getSimpleName();// int String boolean
// type需要进行转换 int --> integer, String text;
sb.append(name).append(DaoUtil.getColumnType(type)).append(", ");
}
sb.replace(sb.length() - 2, sb.length(), ")");
String createTableSql = sb.toString();
Log.e(TAG, "表语句--> " + createTableSql);
// 创建表
mSqLiteDatabase.execSQL(createTableSql);
}
// 插入数据库 t 是任意对象
@Override
public long insert(T obj) {
/*ContentValues values = new ContentValues();
values.put("name",person.getName());
values.put("age",person.getAge());
values.put("flag",person.getFlag());
db.insert("Person",null,values);*/
// 使用的其实还是 原生的使用方式,只是我们是封装一下而已
ContentValues values = contentValuesByObj(obj);
// null 速度比第三方的快一倍左右
return mSqLiteDatabase.insert(DaoUtil.getTableName(mClazz), null, values);
}
@Override
public void insert(List<T> datas) {
// 批量插入采用 事物,提高性能
mSqLiteDatabase.beginTransaction();
for (T data : datas) {
// 调用单条插入
insert(data);
}
mSqLiteDatabase.setTransactionSuccessful();
mSqLiteDatabase.endTransaction();
}
private QuerySupport<T> mQuerySupport;
@Override
public QuerySupport<T> querySupport() {
if (mQuerySupport == null) {
mQuerySupport = new QuerySupport<>(mSqLiteDatabase, mClazz);
}
return mQuerySupport;
}
// obj 转成 ContentValues
private ContentValues contentValuesByObj(T obj) {
// 第三方的 使用比对一下 了解一下源码
ContentValues values = new ContentValues();
// 封装values
Field[] fields = mClazz.getDeclaredFields();
for (Field field : fields) {
try {
// 设置权限,私有和共有都可以访问
field.setAccessible(true);
String key = field.getName();
// 获取value
Object value = field.get(obj);
// put 第二个参数是类型 把它转换
mPutMethodArgs[0] = key;
mPutMethodArgs[1] = value;
// 方法使用反射 , 反射在一定程度上会影响性能
//参考AppCompatViewinflater源码
String filedTypeName = field.getType().getName();
// 还是使用反射 获取方法 put 缓存方法
Method putMethod = mPutMethods.get(filedTypeName);
if (putMethod == null) {
putMethod = ContentValues.class.getDeclaredMethod("put",
String.class, value.getClass());
mPutMethods.put(filedTypeName, putMethod);
}
// 通过反射执行
putMethod.invoke(values, mPutMethodArgs);
} catch (Exception e) {
e.printStackTrace();
} finally {
mPutMethodArgs[0] = null;
mPutMethodArgs[1] = null;
}
}
return values;
}
/**
* 删除
*/
public int delete(String whereClause, String[] whereArgs) {
return mSqLiteDatabase.delete(DaoUtil.getTableName(mClazz), whereClause, whereArgs);
}
/**
* 更新 这些你需要对 最原始的写法比较明了 extends
*/
public int update(T obj, String whereClause, String... whereArgs) {
ContentValues values = contentValuesByObj(obj);
return mSqLiteDatabase.update(DaoUtil.getTableName(mClazz),
values, whereClause, whereArgs);
}
}
QuerySupport:专门用来查询的支持类,使用链式调用
public class QuerySupport<T> {
// 查询的列
private String[] mQueryColumns;
// 查询的条件
private String mQuerySelection;
// 查询的参数
private String[] mQuerySelectionArgs;
// 查询分组
private String mQueryGroupBy;
// 查询对结果集进行过滤
private String mQueryHaving;
// 查询排序
private String mQueryOrderBy;
// 查询可用于分页
private String mQueryLimit;
private Class<T> mClass;
private SQLiteDatabase mSQLiteDatabase;
public QuerySupport(SQLiteDatabase sqLiteDatabase, Class<T> clazz) {
this.mClass = clazz;
this.mSQLiteDatabase = sqLiteDatabase;
}
public QuerySupport columns(String... columns) {
this.mQueryColumns = columns;
return this;
}
public QuerySupport selectionArgs(String... selectionArgs) {
this.mQuerySelectionArgs = selectionArgs;
return this;
}
public QuerySupport having(String having) {
this.mQueryHaving = having;
return this;
}
public QuerySupport orderBy(String orderBy) {
this.mQueryOrderBy = orderBy;
return this;
}
public QuerySupport limit(String limit) {
this.mQueryLimit = limit;
return this;
}
public QuerySupport groupBy(String groupBy) {
this.mQueryGroupBy = groupBy;
return this;
}
public QuerySupport selection(String selection) {
this.mQuerySelection = selection;
return this;
}
public List<T> query() {
Cursor cursor = mSQLiteDatabase.query(DaoUtil.getTableName(mClass), mQueryColumns, mQuerySelection,
mQuerySelectionArgs, mQueryGroupBy, mQueryHaving, mQueryOrderBy, mQueryLimit);
clearQueryParams();
return cursorToList(cursor);
}
public List<T> queryAll() {
Cursor cursor = mSQLiteDatabase.query(DaoUtil.getTableName(mClass), null, null, null, null, null, null);
return cursorToList(cursor);
}
/**
* 清空参数
*/
private void clearQueryParams() {
mQueryColumns = null;
mQuerySelection = null;
mQuerySelectionArgs = null;
mQueryGroupBy = null;
mQueryHaving = null;
mQueryOrderBy = null;
mQueryLimit = null;
}
/**
* 通过Cursor封装成查找对象
*
* @return 对象集合列表
*/
private List<T> cursorToList(Cursor cursor) {
List<T> list = new ArrayList<>();
if (cursor != null && cursor.moveToFirst()) {
do {
try {
T instance = mClass.newInstance();
Field[] fields = mClass.getDeclaredFields();
for (Field field : fields) {
// 遍历属性
field.setAccessible(true);
String name = field.getName();
//cursor.getInt(0);
// 获取角标
int index = cursor.getColumnIndex(name);
if (index == -1) {
continue;
}
// 通过反射获取 游标的方法
Method cursorMethod = cursorMethod(field.getType());
if (cursorMethod != null) {
Object value = cursorMethod.invoke(cursor, index);
if (value == null) {
continue;
}
// 处理一些特殊的部分
if (field.getType() == boolean.class || field.getType() == Boolean.class) {
if ("0".equals(String.valueOf(value))) {
value = false;
} else if ("1".equals(String.valueOf(value))) {
value = true;
}
} else if (field.getType() == char.class || field.getType() == Character.class) {
value = ((String) value).charAt(0);
} else if (field.getType() == Date.class) {
long date = (Long) value;
if (date <= 0) {
value = null;
} else {
value = new Date(date);
}
}
field.set(instance, value);
}
}
// 加入集合
list.add(instance);
} catch (Exception e) {
e.printStackTrace();
}
} while (cursor.moveToNext());
}
cursor.close();
return list;
}
private Method cursorMethod(Class<?> type) throws Exception {
String methodName = getColumnMethodName(type);
Method method = Cursor.class.getMethod(methodName, int.class);
return method;
}
private String getColumnMethodName(Class<?> fieldType) {
String typeName;
if (fieldType.isPrimitive()) {//是不是基本类型
typeName = DaoUtil.capitalize(fieldType.getName());//Int
} else {
typeName = fieldType.getSimpleName();//Integer
}
String methodName = "get" + typeName;
if ("getBoolean".equals(methodName)) {
methodName = "getInt";
} else if ("getChar".equals(methodName) || "getCharacter".equals(methodName)) {
methodName = "getString";
} else if ("getDate".equals(methodName)) {
methodName = "getLong";
} else if ("getInteger".equals(methodName)) {
methodName = "getInt";
}
return methodName;
}
}
使用
IDaoSupport<Person> dao = DaoSupportFactory.getFactory().getDao(Person.class);
List<Person> persons = new ArrayList<>();
for (int i = 0; i < 10; i++) {
persons.add(new Person("在线", 18 + i));
}
dao.insert(persons);
List<Person> list = dao.querySupport().queryAll();
Toast.makeText(this, list.size() + "", Toast.LENGTH_SHORT).show();