最近开发的项目中需要使用到ORM框架,但是我并不想针对每一个具体业务写一个Dao,对于通用的CRUD功能,我想试着通过一个BaseDao解决问题,这里涉及到一个关键问题是:如何在编译时获取泛型的实际类型?后来通过抽象类解决了这个问题。
封装
public abstract class BaseDao<T> {
protected static DaoSession daoSession;
public BaseDao(Context context) {
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, dbPath, null);
Database db = helper.getWritableDb();
daoSession = new DaoMaster(db).newSession();
}
public void insert(final T t) {
// 延迟处理异常,所以这里不在构造器中初始化rxDao
try {
final RxDao<T, Void> rxDao = (RxDao<T, Void>) daoSession.getDao(Class.forName(getGenericClassName())).rx();
new Thread(new Runnable() {
@Override
public void run() {
// 当调用订阅操作(即调用Observable.subscribe()方法)的时候,被观察者才真正开始发出事件。
// 核心源码见Observable类的create(OnSubscribe<T> f)方法的解释
rxDao.insert(t).subscribe(new Subscriber<T>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
if (e != null){
e.printStackTrace();
}
}
@Override
public void onNext(T t) {
}
});
}
}).start();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void update(final T t) {
try {
final RxDao<T, Void> rxDao = (RxDao<T, Void>) daoSession.getDao(Class.forName(getGenericClassName())).rx();
new Thread(new Runnable() {
@Override
public void run() {
rxDao.update(t).subscribe(new Subscriber<T>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
if (e != null){
e.printStackTrace();
}
}
@Override
public void onNext(T t) {
}
});
}
}).start();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void delete(final T t) {
try {
final RxDao<T, Void> rxDao = (RxDao<T, Void>) daoSession.getDao(Class.forName(getGenericClassName())).rx();
new Thread(new Runnable() {
@Override
public void run() {
rxDao.delete(t).subscribe(new Subscriber<Void>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
if (e != null){
e.printStackTrace();
}
}
@Override
public void onNext(Void aVoid) {
}
});
}
}).start();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public void loadAll(final ColDaoCallBack<T> colDaoCallBack) {
try {
final RxDao<T, Void> rxDao = (RxDao<T, Void>) daoSession.getDao(Class.forName(getGenericClassName())).rx();
new Thread(new Runnable() {
@Override
public void run() {
rxDao.loadAll()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(colDaoCallBack.getAction1(), new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
if (throwable != null){
throwable.printStackTrace();
}
}
});
}
}).start();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public final Type getType() {
Type superType = getClass().getGenericSuperclass();
Type type = ((ParameterizedType) superType).getActualTypeArguments()[0];
return type;
}
public final String getGenericClassSimpleName() {
String raw = getType().toString();
int spaceIndex = raw.lastIndexOf(" ");
int spotIndex = raw.lastIndexOf(".");
int dollarIndex = raw.lastIndexOf("$");
int index = Math.max(Math.max(spaceIndex, spotIndex), dollarIndex);
String result = raw.substring(index + 1);
return result;
}
public final String getGenericClassName() {
String raw = getType().toString();
int spaceIndex = raw.lastIndexOf(" ");
String result = raw.substring(spaceIndex + 1);
return result;
}
}
实际使用的时候需要创建一个匿名内部类的实例来继承BaseDao抽象类,但是由于CRUD的操作已经在BaseDao中具体实现了,但是只需要提供一个空实现即可,同时传入实际的泛型类型。
具体使用
Bean bean = new Bean();
BaseDao<Bean> baseDao = new BaseDao<>(context){};
baseDao.insert(bean);