1. 程式人生 > >工廠模式實現併發請求多個介面 (同步後臺資料實現離線APP)

工廠模式實現併發請求多個介面 (同步後臺資料實現離線APP)

背景:客戶現場沒有網路,需要在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、模式:工廠模式