架构设计
模块划分
业务模块 :主要业务
数据同步中心模块 :同步数据,上传,下载
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++;
}
});
}
}