工廠模式實現併發請求多個介面 (同步後臺資料實現離線APP)
阿新 • • 發佈:2019-02-18
背景:客戶現場沒有網路,需要在APP上面錄入資訊並上傳後臺伺服器
解決方案:
使用APP之前,先(下載)同步後臺基本資料,同步完成後,客戶直接使用離線版進行資料錄入即可。
具體實現:
方案一、登入APP後,後臺扔過來一個檔案,客戶端去下載(不利於更新資料)
方案二、登入APP後,分線上和離線兩種模式,線上模式同步後臺的基本資料後,離線模式就可以直接使用了。
採用多介面請求,判斷上次的更新時間,來實現後臺新新增的資料進行本地資料的更新
下面具體介紹方案二:
先看一個工廠模式的反射版本
public abstract class Factory {
public abstract <T extends Product> T createProduct(Class<T> clz);
}
//具體工廠
public class ConcreteFactory extends Factory {
@Override
public <T extends Product> T createProduct(Class<T> clz) {
Product product = null;
try {
product = (Product) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T)product;
}
}
//客戶端
Factory factory = new ConcreteFactory();
Product product = factory.createProduct(ConcreteProductB.class);
product.method();
根據需求,我們就同步產品、批次、機構作為案例
下面我們就用這種方式來實現併發求多個介面,並監聽所有介面資料請求結束並返回
public abstract class SynFactory {
public abstract <T extends AbsBaseSyn> T createSyn(Class<T> clz);
}
//具體工廠
public class SynConcreteFactory extends SynFactory {
@Override
public <T extends AbsBaseSyn> T createSyn(Class<T> clz) {
AbsBaseSyn baseSyn = null;
try {
baseSyn = (AbsBaseSyn) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) baseSyn;
}
}
//定義抽象方法
public abstract class AbsBaseSyn {
public abstract void init(Context context, FragmentManager fragmentManager, SynDialogFragment synDialogFragment, ExecutorService cachedThreadPool);
/**
* 產品類的抽象方法
* 由具體的產品類去實現
*/
public abstract ApiRequest syn(int page);
public abstract void cancle(boolean isCancle);
public abstract void continueRequest(int page, String tag);
}
//具體實現父類
public class BaseSyn extends AbsBaseSyn {
protected Context mContext;
protected FragmentManager mFragmentManager;
protected SynDialogFragment mSynDialogFragment;
protected UpdateTimeDao mUpdateTimeDao;
public static boolean isCancle;
private ExecutorService cachedThreadPool;
//開始同步
@Override
public ApiRequest syn(int page) {
return null;
}
//取消請求
@Override
public void cancle(boolean isCancle) {
this.isCancle = isCancle;
}
//繼續請求下一頁
@Override
public void continueRequest(int page, String tag) {
Log.v("tag", tag);
if(!isCancle) {
syn(page);
}
}
//初始化
@Override
public void init(Context context, FragmentManager fragmentManager, SynDialogFragment synDialogFragment,
ExecutorService cachedThreadPool) {
this.mContext = context;
mFragmentManager = fragmentManager;
this.mSynDialogFragment = synDialogFragment;
this.cachedThreadPool = cachedThreadPool;
mUpdateTimeDao = new UpdateTimeDao();
}
//儲存所有資料
protected void save(final IBaseDao baseDao, final int message, final List list, final String function) {
if(!cachedThreadPool.isShutdown()) {
cachedThreadPool.execute(new SynSave(baseDao, message, list, function));
}
}
//-----------------------------------------loading------------------------------------------
//取消loading dialog
protected void dismissSyning() {
if (null != mSynDialogFragment) {
mSynDialogFragment.dismiss();
}
}
//渲染錯誤的dialog
protected void showError(String result) {
dismissSyning();
cancle(true);
showErrorDialog(result);
}
private void showErrorDialog(String result) {
final CommonDialogFragment fragment = new CommonDialogFragment();
fragment.setResult("同步失敗")
.setType(1)
.setResultDetails(result)
.setRightButtonStr("好的")
.setOnButtonClickListener(new CommonDialogFragment.OnButtonClickListener() {
@Override
public void onLeftButtonClick(View v) {
}
@Override
public void onRightButtonClick(View v) {
}
});
fragment.showDialog("切換至線上", mFragmentManager);
}
}
//同步完成就傳送訊息
public class SynHandle extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
EventBus.getDefault().post(new SynProgressEvent(msg));
}
}
//儲存資料的方法
public class SynSave implements Runnable{
private IBaseDao baseDao;
private int message;
private List list;
private String function;
private SynHandle mSynHandle;
public SynSave(final IBaseDao baseDao, final int message, final List list, final String function) {
this.baseDao = baseDao;
this.message = message;
this.list = list;
this.function = function;
mSynHandle = new SynHandle();
}
@Override
public void run() {
baseDao.firstUpdateList(list);
setUpdateTime(function);
BaseTools.putFirstUser(function);
mSynHandle.sendEmptyMessage(message);
}
private void setUpdateTime(final String columns) {
GetSystemTimeRequest request = new GetSystemTimeRequest<GetSystemTimeResponse>() {
@Override
public void onLogicSuccess(GetSystemTimeResponse response) {
super.onLogicSuccess(response);
String time = response.getData().getSysInfo().getTime();
//改為每個使用者都有多個更新時間,比如產品列表一個、批次列表一個
new UpdateTimeDao().setUpdateTime(time, columns);
}
};
request.get();
}
}
下面具體的請求類:產品資料請求、批次資料請求、機構資料請求
//產品資料同步
public class ProductSyn extends BaseSyn {
GetProductListRequest mGetProductListRequest;
private List<Product> mProductList = new ArrayList<>();
private int mProductListPage = 1;
public ProductSyn() {
mProductList.clear();
}
@Override
public ApiRequest syn(final int page) {
super.syn(page);
initProductList(page);
return mGetProductListRequest;
}
@Override
public void cancle(boolean isCancle) {
super.cancle(isCancle);
}
private void initProductList(final int page) {
if (page == 1) {
Log.v("tag", "initProductList");
}
mGetProductListRequest = new GetProductListRequest<GetProductListRespons>() {
@Override
public void onStart() {
super.onStart();
}
@Override
public void onLogicSuccess(GetProductListRespons respons) {
super.onLogicSuccess(respons);
List<Product> list = respons.getData().getProductList();
if (ListUtils.isEmpty(list)) {
save(new ProductDao(), Contacts.M_PRODUCT, mProductList, UpdateTimeDao.PRODUCT_TIME);
return;
}
mProductListPage = page + 1;
mProductList.addAll(list);
continueRequest(mProductListPage, "initProductList"+page);
}
@Override
public void onLogicFailure(GetProductListRespons respons) {
super.onLogicFailure(respons);
showError("initProductList" + respons.getError());
dismissSyning();
}
@Override
public void onFailure(int errorCode, String msg) {
super.onFailure(errorCode, msg);
showError(errorCode + msg);
dismissSyning();
}
};
GetProductListRequest.Param param = new GetProductListRequest.Param();
param.setUpdateTime(mUpdateTimeDao.getUpdateTime(UpdateTimeDao.PRODUCT_TIME));
param.setPageNum(page);
param.setPageSize(Contacts.PAGE_SIZE_1000);
mGetProductListRequest.setParam(param);
mGetProductListRequest.get();
}
}
//批次資料同步
public class BatchSyn extends BaseSyn {
GetProductBatchListRequest mGetProductBatchListRequest;
private List<Batch> mBatchList = new ArrayList<>();
private int mBatchListPage = 1;
public BatchSyn() {
mBatchList.clear();
}
@Override
public ApiRequest syn(final int page) {
super.syn(page);
initBatchList(page);
return mGetProductBatchListRequest;
}
private void initBatchList(final int page) {
if (page == 1) {
Log.v("tag", "initBatchList");
}
mGetProductBatchListRequest = new GetProductBatchListRequest<GetProductBatchListRespons>() {
@Override
public void onStart() {
super.onStart();
}
@Override
public void onLogicSuccess(GetProductBatchListRespons respons) {
super.onLogicSuccess(respons);
List<Batch> list = respons.getData().getProductBatchList();
if (ListUtils.isEmpty(list)) {
save(new BatchDao(), Contacts.M_BATCH, mBatchList, UpdateTimeDao.PRODUCTBATCH_TIME);
return;
}
mBatchListPage = page + 1;
mBatchList.addAll(list);
continueRequest(mBatchListPage, "initBatchList"+page);
}
@Override
public void onLogicFailure(GetProductBatchListRespons respons) {
super.onLogicFailure(respons);
showError("initBatchList" + respons.getError());
dismissSyning();
}
@Override
public void onFailure(int errorCode, String msg) {
super.onFailure(errorCode, msg);
showError(errorCode + msg);
dismissSyning();
}
};
GetProductBatchListRequest.Param param = new GetProductBatchListRequest.Param();
param.setUpdateTime(mUpdateTimeDao.getUpdateTime(UpdateTimeDao.PRODUCTBATCH_TIME));
param.setPageNum(page);
param.setPageSize(Contacts.PAGE_SIZE_1000);
mGetProductBatchListRequest.setParam(param);
mGetProductBatchListRequest.get();
}
}
//機構資料同步
public class OrgSyn extends BaseSyn {
GetOrgListRequest mGetOrgListRequest;
private List<Org> mOrgList = new ArrayList<>();
private int mOrgListPage = 1;
public OrgSyn() {
mOrgList.clear();
}
@Override
public ApiRequest syn(final int page) {
super.syn(page);
initOrgList(page);
return mGetOrgListRequest;
}
private void initOrgList(final int page) {
if (page == 1) {
Log.v("tag", "initOrgList");
mOrgList.clear();
}
mGetOrgListRequest = new GetOrgListRequest<GetOrgListRespons>() {
@Override
public void onStart() {
super.onStart();
}
@Override
public void onLogicSuccess(GetOrgListRespons respons) {
super.onLogicSuccess(respons);
List<Org> list = respons.getData().getRows();
if (ListUtils.isEmpty(list)) {
save(new OrgDao(), Contacts.M_ORG, mOrgList, UpdateTimeDao.ORG_TIME);
return;
}
mOrgListPage = page + 1;
mOrgList.addAll(list);
continueRequest(mOrgListPage, "initOrgList" + mOrgListPage);
}
@Override
public void onLogicFailure(GetOrgListRespons respons) {
super.onLogicFailure(respons);
showError("initOrgList" + respons.getError());
dismissSyning();
}
@Override
public void onFailure(int errorCode, String msg) {
super.onFailure(errorCode, msg);
showError(errorCode + msg);
dismissSyning();
}
};
GetOrgListRequest.Param param = new GetOrgListRequest.Param();
param.setLastUpdateTimeBegin(mUpdateTimeDao.getUpdateTime(UpdateTimeDao.ORG_TIME));
param.setPageNum(page);
param.setPageSize(Contacts.PAGE_SIZE_1000);
param.setOrderField("LastUpdateTime");
mGetOrgListRequest.setParam(param);
mGetOrgListRequest.get();
}
}
最後客戶端呼叫:
//1、首先建立一個class陣列
private Class<AbsBaseSyn>[] synClass = new Class[]{
ProductSyn.class,
BatchSyn.class,
OrgSyn.class
};
//2、開始同步
private void doSync() {
mSynFactory = new SynConcreteFactory();
resetSyn();
cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < synClass.length; i++) {
AbsBaseSyn basesyn = mSynFactory.createSyn(synClass[i]);
basesyn.init(getContext(), getFragmentManager(), mSynDialogFragment, cachedThreadPool);
basesyn.syn(1);
}
}
//3、同步結束後在onProgressEvent中取完成後的訊息
private int progress;
private boolean messageState;
private List<Integer> mMessageList = new ArrayList<>();
@Subscribe(threadMode = ThreadMode.MAIN)
public void onProgressEvent(SynProgressEvent event) {
Message msg = event.getMsg();
for (int i = 0; i < mMessageList.size(); i++) {
if (msg.what == Contacts.MESSAGES[i]) {
mMessageList.set(i, msg.what);
progress = progress + (100 / mMessageList.size());
//傳遞進度
setUploadProgress(progress);
break;
}
}
for (int i = 0; i < mMessageList.size(); i++) {
if (mMessageList.get(i) == 0) {
messageState = true;
break;
}
}
if (!messageState) {
//同步完成
dismissSyning();
resetSyn();
}
messageState = false;
}
是怎麼做到監聽所有請求都返回成功了,再彈出同步成功?
列印一下mMessageList的資料變化,你就知道了
Log.d("tag",
"[ " + mMessageList.get(0) + ","
+ mMessageList.get(1) + ","
+ mMessageList.get(2) + ","
+ " ]"
);
如圖,只要有一個請求返回了,就會更新一次mMessageList,直到mMessageList中沒有0,那麼就同步成功了。
其他的一些支援類和方法:
public static final int M_PRODUCT = 1;
public static final int M_BATCH = 2;
public static final int M_ORG = 3;
public static final int MESSAGES[] = {
M_PRODUCT,
M_BATCH,
M_ORG
};
//重置同步屬性
private void resetSyn() {
resetCancle();
progress = 0;
resetMsg();
}
//重置mMessageList,使mMessageList中是3個0
private void resetMsg() {
mMessageList.clear();
for (int i = 0; i < Contacts.MESSAGES.length; i++) {
mMessageList.add(0);
}
}
//取消請求
private void cancleSyn() {
for (int i = 0; i < synClass.length; i++) {
AbsBaseSyn basesyn = mSynFactory.createSyn(synClass[i]);
basesyn.cancle(true);
}
if(cachedThreadPool != null) {
cachedThreadPool.shutdown();
}
}
//重置請求取消
private void resetCancle() {
for (int i = 0; i < synClass.length; i++) {
AbsBaseSyn basesyn = mSynFactory.createSyn(synClass[i]);
basesyn.cancle(false);
}
}
下面展示下所有類:
附加:用到的知識點:
1、持久層:litepal
2、請求:OKHttp
3、Executors執行緒池
4、彈框:DialogFragment
5、訊息:EventBus
6、模式:工廠模式