任何項目中都應該有公共數據的維護系統,然而公共數據的維護也是一項耗時耗力的工作。
以用戶信息爲例:
* 方案一:採用靜態類
用戶信息包含用戶的基本屬性,狀態等,許多項目中會簡單使用靜態類來保存用戶信息。
採用靜態類保存用戶信息可能在手機內存不夠的情況下被虛擬機釋放(請參考jvm垃圾回收機制)。
一旦用戶靜態類被釋放,項目中調用時會面臨着這空指針而導致app崩潰的風險。
* 方案二:採用數據庫+單例
將用戶信息保存到數據庫,採用單例實例化數據庫中的用戶信息,這樣方式的確避免了被釋放的危險,但沒有處理用戶信息聯動效應。
若用戶信息在改變時,其他使用的地方就沒有辦法獲取最新信息並刷新UI了。
* 結合以上需求以及問題,編寫一個簡潔的數據管理系統,提供公共數據單例,集合數據改變回調通知業務。
基於Realm、OkHttp3封裝的公共數據管理系統:DMS
Demo已上傳至github
github:https://github.com/MrZhousf/DMS
相關代碼
/**
* DMS基類
* @author: zhousf
*/
public abstract class BaseDMS<T extends RealmObject> {
protected abstract List<T> doHttp(Object[] params);
protected abstract Class initModelClass();
final List<DMSChangeListener<T>> changeListeners = new CopyOnWriteArrayList<>();
static ExecutorService executorService;
T model;
List<T> modelList;
String failedResult;
/**
* 發送網絡獲取數據命令
* @param listener 監聽器
* @param params 參數
*/
public void push(final DMSListener<T> listener, final Object... params){
//初始化線程池
initExecutorService();
executorService.execute(new Runnable() {
@Override
public void run() {
//初始化回調信息
Result<T> result = new Result<T>();
result.setSuccessful(false);
failedResult = "獲取網絡數據失敗";
try {
//從網絡獲取數據
List<T> list = doHttp(params);
if(null != list && list.size() > 0){
//保存數據庫
if(insertBeforeDeleteAll(list)){
T model = list.get(0);
result.setModel(model);
result.setModelList(list);
result.setSuccessful(true);
result.setRetDetail("操作成功");
//數據改變回調
changeModelCallback(result);
}
}else{
result.setRetDetail(failedResult);
}
} catch (Exception e){
result.setRetDetail(failedResult+":"+e.getMessage());
}
//操作結果回調
if(null != listener){
Message resMsg = new MainMessage<T>(
DMSMainHandler.CALLBACK_RESPONSE,
result,
listener)
.build();
DMSMainHandler.getInstance().sendMessage(resMsg);
}
init();
}
});
}
/**
* 添加DMS模型改變監聽
*/
public void addChangeListener(DMSChangeListener<T> listener){
if (null == listener) {
throw new IllegalArgumentException("Listener should not be null");
}
if (!changeListeners.contains(listener)) {
changeListeners.add(listener);
}
}
/**
* 移除DMS模型改變監聽
*/
public void removeChangeListener(DMSChangeListener listener){
if (listener == null) {
throw new IllegalArgumentException("Listener should not be null");
}
if(changeListeners.contains(listener)){
changeListeners.remove(listener);
}
}
protected List<T> modelToList(T model){
List<T> list = new ArrayList<>();
if(null != model)
list.add(model);
return list;
}
protected void setFailedResult(String failedResult) {
this.failedResult = failedResult;
}
void initExecutorService(){
if(null == executorService){
executorService = Executors.newCachedThreadPool();
}
}
/**
* 模型改變時回調
*/
void changeModelCallback(Result<T> result){
try {
for(DMSChangeListener<T> listener : changeListeners){
Message changeMsg = new MainMessage<T>(
DMSMainHandler.CALLBACK_CHANGE,
result,
listener)
.build();
DMSMainHandler.getInstance().sendMessage(changeMsg);
}
}catch (Exception e){
e.printStackTrace();
}
}
boolean insertBeforeDeleteAll(List<T> model){
return RealmUtil.getInstance().insertBeforeDeleteAll(model);
}
List<T> getDataFromDB(Class clazz){
return RealmUtil.getInstance().findAll(clazz);
}
/**
* 初始化數據模型
*/
protected void init(){
Class clazz = initModelClass();
if(null == clazz)
throw new IllegalArgumentException("please override the abstract method initModelClass and return an value of available!");
List<T> list = getDataFromDB(clazz);
modelList = new ArrayList<>();
if(null != list && list.size() > 0){
modelList = list;
model = modelList.get(0);
}else{//自動實例化防止獲取數據時空指針
try {
model = (T) clazz.newInstance();
initStringFields(model);
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
* 初始化String成員變量
*/
void initStringFields(T model){
Field[] fields = model.getClass().getDeclaredFields();
if(null != fields){
try {
for(int i=0;i<fields.length;i++){
if(fields[i].getType() == String.class){
fields[i].setAccessible(true);
fields[i].set(model,"");
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public T getModel() {
return model;
}
public List<T> getModelList() {
return modelList;
}
}