工厂模式实现并发请求多个接口 (同步后台数据实现离线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、模式:工厂模式

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页