工厂模式实现并发请求多个接口 (同步后台数据实现离线APP)

Posted 大雄童鞋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了工厂模式实现并发请求多个接口 (同步后台数据实现离线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、模式:工厂模式

以上是关于工厂模式实现并发请求多个接口 (同步后台数据实现离线APP)的主要内容,如果未能解决你的问题,请参考以下文章

一个简单的工厂模式(一个接口,多个实现,通过调用条件的不同,分别去调用符合的实现)

设计模式重新理解简单工厂模式工厂模式抽象工厂模式

半同步/半异步并发模式进程池实现

设计模式——工厂方法模式(Factory Method)

Spring 实现两种设计模式:工厂模式和单态模式

工厂模式