离线应用同步数据模块学习总结

架构设计

模块划分

业务模块 :主要业务

数据同步中心模块 :同步数据,上传,下载

data_sync:实现数据使用接口 及上传下载功能
data_sync_api:对外提供数据使用接口

设置模块:设置端口号和ip

setting :设置,登录,锁屏页
setting_api:提供获取端口号和ip相关接口

其他模块:功能性模块

数据同步模块

DataSyncActivity

视图层需要监听网络环境变化,注册广播接收器,网络环境一旦断开,就关闭当前页,进去业务页面,锁屏页,否则进行同步

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(MyNetStateReceiver.ACTION_NET_TATE_CHANGE);
        registerReceiver(receiver, intentFilter);//注册广播接收器,接收CONNECTIVITY_CHANGE这个广播
    }

MyNetStateReceiver

public class MyNetStateReceiver extends BroadcastReceiver {

        public static final String ACTION_NET_TATE_CHANGE = "android.net.conn.CONNECTIVITY_CHANGE";

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo ethernetInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
            NetworkInfo wifiInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            boolean isEthernetConnected = false;
            boolean isWifiConnected = false;
            if (ethernetInfo != null) {
                isEthernetConnected = ethernetInfo.isConnected();
            }
            if (wifiInfo != null) {
                isWifiConnected = wifiInfo.isConnected();
            }
            if (!isEthernetConnected && !isWifiConnected) {
                finish();
            }
        }
    }

不要忘记 解绑

 @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

开始同步

private void startSyncTask() {
        List<String> classList = new ArrayList<>();
        //添加任务
        classList.add("com.mobile.securitycheck.datasync.task.DownloadRecord");
        classList.add("com.mobile.securitycheck.datasync.task.SecondTask");
        classList.add("com.mobile.securitycheck.datasync.task.ThirdTask");
        dataSyncManager = new CBPDataSyncManager();
        dataSyncManager.init(classList);
        dataSyncManager.setDataSyncCallback(new DataSyncCallback() {
            @Override
            public void onStart() {
                BCLLog.d("onStart");
                if (getView() == null) {
                    BCLLog.e("view is null");
                    return;
                }
                //view 层提示开始同步
                getView().showSyncStartText();
            }

            @Override
            public void onProgress(DataSyncTaskType type, int progress, int totalProgress) {
                BCLLog.d("type = " + type + ", progress = " + progress);
                if (getView() == null) {
                    BCLLog.e("view is null");
                    return;
                }
                if (type == DataSyncTaskType.Upload) {
                    getView().changeUploadProgress(progress);
                } else if (type == DataSyncTaskType.Download) {
                    getView().changeDownloadProgress(progress);
                }
                //更新总进度
                getView().changeTotalProgress(totalProgress);
            }

            @Override
            public void onComplete() {
                BCLLog.d("onComplete");
                if (getView() == null) {
                    BCLLog.e("view is null");
                    return;
                }
                  //view 层提示同步完成
                getView().showSyncCompleteText();
            }
        });
        dataSyncManager.start();
        //间隔时间,单位分钟
        dataSyncManager.startTimer(60);
    }

CBPDataSyncManager

public class CBPDataSyncManager implements DataSyncTaskCallback {

    private List<IDataSyncTask> taskList;
    private int uploadCount;
    private int uploadSuccessCount;
    private int uploadFailedCount;
    private int downloadCount;
    private int downloadSuccessCount;
    private int downloadFailedCount;
    private DataSyncCallback dataSyncCallback;
    private Timer dataSyncTimer;
    private boolean syncing;
    private Handler mainHandler = new Handler(Looper.getMainLooper());

    public void init(List<String> taskClassList) {
        //反射创建task集合
        if (taskClassList == null || taskClassList.isEmpty()) {
            BCLLog.e("taskClassList is empty");
            return;
        }
        taskList = new ArrayList<>();
        for (String className : taskClassList) {
            try {
                //反射创建同步任务
                Class<?> clazz = Class.forName(className);
                IDataSyncTask task = (IDataSyncTask) clazz.newInstance();
                //设置任务回调
                task.setCallback(this);
                DataSyncTaskType taskType = task.getTaskType();
                if (taskType == DataSyncTaskType.Upload) {
                    uploadCount++;
                } else if (taskType == DataSyncTaskType.Download) {
                    downloadCount++;
                } else {
                    continue;
                }
                //添加到任务列表
                taskList.add(task);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置同步管理器的回调
     *
     * @param dataSyncCallback 回调
     */
    public void setDataSyncCallback(DataSyncCallback dataSyncCallback) {
        this.dataSyncCallback = dataSyncCallback;
    }

    /**
     * 开启自动同步定时器
     *
     * @param repeatTimeInMinute 间隔时间,单位分钟
     */
    public void startTimer(int repeatTimeInMinute) {
        //开启定时器
        if (dataSyncTimer != null) {
            dataSyncTimer.cancel();
        }
        dataSyncTimer = new Timer();
        dataSyncTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                if (!syncing) {
                    mainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            start();
                        }
                    });
                }
            }
        }, repeatTimeInMinute * 60 * 1000, repeatTimeInMinute * 60 * 1000);
    }

    /**
     * 开始执行所有任务
     */
    public void start() {
        if (taskList == null || taskList.isEmpty()) {
            BCLLog.e("taskList is null, can not start");
            return;
        }
        if (syncing) {
            BCLLog.e("sync already start");
            return;
        }
        syncing = true;

        if (dataSyncCallback != null) {
            dataSyncCallback.onStart();
        }
        resetProgress();
        for (IDataSyncTask task : taskList) {
            if (task != null) {
                task.start();
            }
        }
    }

    /**
     * 停止执行所有任务
     */
    public void stop() {
        syncing = false;
        if (taskList == null || taskList.isEmpty()) {
            BCLLog.e("taskList is null, can not stop");
            return;
        }
        for (IDataSyncTask task : taskList) {
            if (task != null) {
                task.stop();
            }
        }
        //取消timer
        if (dataSyncTimer != null) {
            dataSyncTimer.cancel();
        }
    }

    /**
     * 重置同步进度
     */
    private void resetProgress() {
        if (dataSyncCallback != null) {
            //开始的时候进度回调0
            dataSyncCallback.onProgress(DataSyncTaskType.Download, 0, 0);
            dataSyncCallback.onProgress(DataSyncTaskType.Upload, 0, 0);
        }
        uploadSuccessCount = 0;
        uploadFailedCount = 0;
        downloadSuccessCount = 0;
        downloadFailedCount = 0;
    }

    /**
     * 刷新同步进度
     */
    private void updateProgress() {
        if (taskList == null) {
            BCLLog.e("taskList is null");
            return;
        }
        //上传进度
        float uploadProgressFloat = (float) (uploadSuccessCount + uploadFailedCount) / (float) uploadCount;
        int uploadProgress = (int) (uploadProgressFloat * 100);
        //下载进度
        float downloadProgressFloat = (float) (downloadSuccessCount + downloadFailedCount) / (float) downloadCount;
        int downloadProgress = (int) (downloadProgressFloat * 100);
        //总进度是(上传+下载)/2
        int totalProgress = (int) ((uploadProgressFloat + downloadProgressFloat) / 2f * 100);
        if (dataSyncCallback != null) {
            dataSyncCallback.onProgress(DataSyncTaskType.Upload, uploadProgress, totalProgress);
        }
        if (dataSyncCallback != null) {
            dataSyncCallback.onProgress(DataSyncTaskType.Download, downloadProgress, totalProgress);
        }
        //是否全部完成
        if (taskList.size() == (uploadSuccessCount + uploadFailedCount + downloadSuccessCount + downloadFailedCount)) {
            syncing = false;
            if (dataSyncCallback != null) {
                dataSyncCallback.onComplete();
            }
        }
    }

    //<editor-fold desc="DataSyncTaskCallback实现">
    @Override
    public void onSuccess(DataSyncTaskType type) {
        if (type == DataSyncTaskType.Upload) {
            uploadSuccessCount++;
        } else if (type == DataSyncTaskType.Download) {
            downloadSuccessCount++;
        }
        updateProgress();
    }

    @Override
    public void onFailed(DataSyncTaskType type, Throwable throwable) {
        if (type == DataSyncTaskType.Upload) {
            uploadFailedCount++;
        } else if (type == DataSyncTaskType.Download) {
            downloadFailedCount++;
        }
        updateProgress();
    }

    @Override
    public void onCancel(DataSyncTaskType type) {
        if (type == DataSyncTaskType.Upload) {
            uploadFailedCount++;
        } else if (type == DataSyncTaskType.Download) {
            downloadFailedCount++;
        }
        updateProgress();
    }
    //</editor-fold>
}

同步任务回调

/**
 * 同步任务回调
 */
public interface DataSyncTaskCallback {

    /**
     * 任务执行成功
     * @param type 任务类型
     */
    void onSuccess(DataSyncTaskType type);

    /**
     * 任务执行失败
     * @param type 任务类型
     * @param throwable 异常信息
     */
    void onFailed(DataSyncTaskType type, Throwable throwable);

    /**
     * 任务取消
     * @param type 任务类型
     */
    void onCancel(DataSyncTaskType type);

}

任务类型


/**
 * 任务类型
 */
public enum DataSyncTaskType {

    /**
     * 未知
     */
    UNKNOWN,
    /**
     * 上传类任务
     */
    Upload,
    /**
     * 下载类任务
     */
    Download
}

下载 以DownloadRecordTask举例

public class DownloadCheckRecordTask extends BaseDataSyncTask {


    private static final String TAG = "DownloadRecordTask";
    private static int PAGE_SIZE = 50;
    private int currentPageNum = 1;
    private List<Record> recordList;
    private ExecutorService executor;
    private List<RecordPo> poList;
    private INetPlugin netPlugin;

    @Override
    public DataSyncTaskType getTaskType() {
        return DataSyncTaskType.Download;
    }

    @Override
    public void start() {
        netPlugin = PluginProvider.getInstance().getNetPlugin();
        if (netPlugin == null) {
            onTaskFailed(new Throwable("netPlugin is null"));
            return;
        }
        recordList = new ArrayList<>();
        poList = new ArrayList<>();
        //创建线程池,线程数应大于1,因为EndTask会占用一个线程
        executor = Executors.newFixedThreadPool(6);
        getRecordList(currentPageNum);
    }

    private void getRecordList(int pageNum) {
        if (netPlugin == null) {
            onTaskFailed(new Throwable("netPlugin is null"));
            return;
        }
        SyncRecordPo syncRecordPo = GreenDaoHelper.getCheckRecordListSyncRecord();
        //如果没有同步记录,说明是首次同步,updateTime为null
        Date updateTime = null;
        if (syncRecordPo != null && syncRecordPo.getLastUpdateTime() != 0) {
            updateTime = new Date(syncRecordPo.getLastUpdateTime());
        }
        //请求参数
        Map<String, Object> params = new HashMap<>();
        params.put("pageNum", pageNum);
        params.put("pageSize", PAGE_SIZE);
        //首次全量更新不传updateTime
        if (updateTime != null) {
            params.put("updateTime", TimeUtils.date2String(updateTime, UPDATE_TIME_FORMAT));
        }
        netPlugin.getCheckRecordList(params, new NetPluginHttpCallback<NetPluginGetCheckRecordResponse>() {
            @Override
            public void onFailure(Throwable throwable) {
                onTaskFailed(throwable);
            }

            @Override
            public void onSuccess(NetPluginGetCheckRecordResponse responseData) {
                if (responseData == null) {
                    LogUtils.e("response is null");
                    onTaskFailed(new Throwable("response is null"));
                    return;
                }
                List<NetPluginCheckRecord> content = responseData.getContent();
                if (content == null) {
                    LogUtils.e("content is null");
                    onTaskFailed(new Throwable("content is null"));
                    return;
                }
                recordList.addAll(content);
                if (content.size() < PAGE_SIZE) {
                    downloadAndSaveToDB();
                } else {
                    getRecordList(++currentPageNum);
                }
            }
        });
    }

    private void downloadImageAndSaveToDB() {
        if (recordList.isEmpty()) {
            onTaskSuccess();
            return;
        }
        int taskSize = recordList.size();
        //根据modules数量创建计数锁
        CountDownLatch taskLatch = new CountDownLatch(taskSize);
        //创建负责回调上层的任务
        EndTask endTask = new EndTask(taskLatch);
        executor.execute(endTask);
        //根据module数量创建多个获取api的任务
        for (NetPluginCheckRecord checkRecord : recordList) {
            JobTask jobTask = new JobTask(taskLatch, checkRecord);
            executor.execute(jobTask);
        }
    }

    class EndTask implements Runnable {
        private CountDownLatch endTaskLatch;

        EndTask(CountDownLatch latch) {
            this.endTaskLatch = latch;
        }

        public void run() {
            try {
                endTaskLatch.await();
                LogUtils.d(TAG, "开始执行EndTask," + endTaskLatch.getCount());
                //保存到数据库
                for (RecordPo recordPo : poList) {
                    GreenDaoHelper.saveRecord(recordPo);
                }
                //更新同步时间
                GreenDaoHelper.updateCheckRecordListSyncRecord();
                onTaskSuccess();
            } catch (Exception e) {
                e.printStackTrace();
                LogUtils.d(TAG, "EndTask 出错..." + e.getMessage());
            }
        }
    }

    class JobTask implements Runnable {

        private CountDownLatch endTaskLatch;
        private NetPluginCheckRecord record;

        public JobTask(CountDownLatch latch, NetPluginRecord record) {
            this.endTaskLatch = latch;
            this.record= record;
        }

        public void run() {
            if (record== null) {
                endTaskLatch.countDown();
                return;
            }
            LogUtils.d(TAG, "JobTask 开始...id = " + checkRecord.getId());
            //创建记录po
            CheckRecordPo checkRecordPo = new CheckRecordPo();
            //保存记录
            GreenDaoHelper.saveRecord(checkRecordPo);
            // 计数减一
            endTaskLatch.countDown();
        }
    }
}

上传 UploadRecordTask

public class UploadRecordTask extends BaseDataSyncTask {

    private static final String UPLOAD_FILE_KEY = "sendfile";
    private static final String UPLOAD_FILE_NAME = "file.png";
    private INetPlugin netPlugin;
    private int count;//待上传的记录总数
    private int successCount;//上传成功的记录数
    private int failedCount;//上传失败的记录数

    @Override
    public void start() {
        netPlugin = PluginProvider.getInstance().getNetPlugin();
        if (netPlugin == null) {
            onTaskFailed(new Throwable("netPlugin is null"));
            return;
        }
        uploadFile();
    }

    @Override
    public DataSyncTaskType getTaskType() {
        return DataSyncTaskType.Upload;
    }

    private void uploadFile() {
        Map<String, String> params = new HashMap<>();
        params.put("fileName", UPLOAD_FILE_NAME);//fileName 必填
        params.put("filePath", photoPath);
        PluginProvider.getInstance().getNetPlugin().uploadFile(params, new NetPluginHttpCallback<NetPluginUploadFileResponse>() {
            @Override
            public void onFailure(Throwable throwable) {
               failedCount++
            }

            @Override
            public void onSuccess(NetPluginUploadFileResponse responseData) {
               successCount++}
        });
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值