您的位置:首页 > 移动开发 > Android开发

Android TV开发--实现屏保图片云端可配置

2016-04-19 21:06 513 查看

功能描述:

 在TV上,出厂时会默认配置一组屏保图片,用作屏保初期展示。

 但作为运营的工具之一,当然会希望屏保图片可以在云端配置,若未配置则采用系统默  认图片。

 若配置了一组新的图片,则需要下载到本地,在下次启动屏保时用来展示。



功能明确点:

1.屏保check时机:屏保启动

2.新屏保使用时机:屏保启动

3.屏保从云端下载图片后保存路径:

../files/screenPic/pathA/

../files/screenPic/pathB/

此处采用A/B目录来保存,便于在使用一组的同时下载另一组,类似于A/B系统

4.旧目录中图片删除时机:屏保退出时,发现刚进入时screenPath与退出时screenPath不一致(表示已同步成功,则删除之前使用目录中的图片)

5.支持设置屏保同步百分比阈值,大于该阈值则认为同步成功(比如10张成功8张以上),下次启动需要使用新屏保。 使用该目录屏保后,check云端时间与本地时间一致且发现上次未完全同步成功,则继续同步剩余未成功的图片。


图片同步流程图:





流程提示:
1.在屏保进入时,check下载信息,根据云端、上次同步时间戳

2.在网络请求成功回调中开始图片同步

3.同步时需要判断图片是否已经在本地存在,若存在则copy,否则下载

4.整理出copy list和download list

5.下载包括MD5 check 机制和retry重试3次机制

6.当copy完毕且download完毕,统计成功率是否大于阈值

7.大于阈值值存屏保新路径,若达到100%则保存完整下载FullDLFlag


 补充:此处使用Json,来保存图片下载信息、图片copy,屏保按照云端配置的顺序显示,所以需要使用一种数据结构来存储相关信息,这里使用Json,通过更新Json信息达到,下载、使用图片的目的。

  

  下面是代码说明部分

    1.触发屏保图片同步入口

   
/**
* picture whether need to update
* this class call downloadhelper to download picture
* @author WMB
*/
public class PicCheckHelper {
private static PicCheckHelper instance = null;
private BaseTimer mTimer = null;
private static final int REQUESTINTERVAL = 60 * 1000; // 2 * 60 * 60 * 1000

public static PicCheckHelper getInstance(){
if(null == instance){
instance = new PicCheckHelper();
}
return instance;
}

/**
* start 2h Timer
*/
public void start(){
if(null == mTimer){
mTimer = new BaseTimer();
}
mTimer.startInterval(REQUESTINTERVAL, mTimerCallback);
}

/**
* close Timer
*/
public void close(){
if(null != mTimer){
mTimer.killTimer();
}
}

/**
* check right now
*/
public void checkNow(){
checkPic();
}

/**
* check picture whether need to update by cloud request
*/
private void checkPic() {
GeneralHttpHelper.getInstance().requestScreenPicUpdate(mHttpCallback);
}

/**
* 定时器回调接口
*/
private TimerCallBack mTimerCallback = new TimerCallBack() {

@Override
public void callback() {
checkPic();
}
};

private HttpCallback mHttpCallback = new HttpCallback() {

@Override
public void onState(HTTP_STATE state) {
switch (state) {
case STATE_SUCCESS:
syncPic();
break;

default:
break;
}
}

};

/**
* 执行图片同步入口
*/
private void syncPic() {
PicSyncHelper.getInstance().syncPicture();
}
}
外部调用checkNow,立刻去云端检查是否有新的屏保,在网络请求成功回调中执行syncPic方法开始同步逻辑。

2.屏保同步解析类(解析云端请求信息)

/**
* 屏保同步解析类
*/
public class ScreenSyncParser extends BaseParser {

@Override
public void run() {
parserScreenData();
}

private void parserScreenData() {
try {
JSONObject jsonObj = new JSONObject(mParseData);
if(jsonObj.optInt("status") < 0){
sendMessage(HTTP_STATE.STATE_ERROR);
LogHelper.releaseLog(PicCons.SCREEN_TAG, "ScreenSyncParser -- http request status < 0");
return;
}
JSONObject data = jsonObj.optJSONObject("data");
String timestamp = data.optString("updatetimes");
LogHelper.releaseLog(PicCons.SCREEN_TAG, "ScreenSyncParser -- parserScreenData cloudtimestamp : "+ timestamp);
Utils.setCloudTimestamp(timestamp);
boolean needsync = compareTimeStamp(timestamp);// 比较云端时间戳与本地时间戳
if(needsync){ // 云端时间新,则保存云端Json信息,为下载做准备(另一种情况:时间戳相等,上次下载80%,则保持之前存的Json不变,继续下载未成功的部分,后面会提到)
JSONArray jsonData = data.optJSONArray("pics");
if(null == jsonData || jsonData.length() == 0){
return;
}
INFO_DL item = null;
ArrayList<INFO_DL> resultList = new ArrayList<INFO_DL>();
for (int i = 0; i < jsonData.length(); i++) {
item = new INFO_DL();
JSONObject jsonItem = jsonData.optJSONObject(i);
item.dlIndex = i;
item.md5 = jsonItem.optString("fileHash");
item.url = jsonItem.optString("url");
item.fileType = Utils.getPicTypeByUrl(item.url);
resultList.add(item);
}
LogHelper.releaseLog(PicCons.SCREEN_TAG, "ScreenSyncParser -- parserScreenData needsync is true ,resultList size: "+resultList.size());
saveDLJson(resultList); // 存到文件中,为下载做准备
Utils.setFullDLFlag(true);// 若云端时间新,则默认上次同步已经完全成功,开始新的同步
}
else{
LogHelper.releaseLog(PicCons.SCREEN_TAG, "ScreenSyncParser -- parserScreenData needsync is false don't need save DLJson");
}
sendMessage(HTTP_STATE.STATE_SUCCESS);
} catch (Exception e) {
sendMessage(HTTP_STATE.STATE_ERROR);
LogHelper.releaseLog(PicCons.SCREEN_TAG, "ScreenSyncParser -- http request error!");
}

}

/**
* compare cloud and local timestamp
* @param cloudTimestamp
* @return true: cloud > local ,false:otherwise
*/
public boolean compareTimeStamp(String cloudTimestamp){
String localTimestamp = Utils.getScreenTimestamp();
if(TextUtils.isEmpty(localTimestamp)){
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- compareTimeStamp localTimestamp is empty, need to sync");
return true;
}
if(TextUtils.isEmpty(cloudTimestamp)){
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- compareTimeStamp cloudTimestamp is empty, don't need to sync");
return false;
}
try {
long localTime = Long.parseLong(localTimestamp);
long cloudTime = Long.parseLong(cloudTimestamp);
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- compareTimeStamp cloudTimestamp is : "+cloudTimestamp+",localTimestamp is: "+localTimestamp);
return cloudTime > localTime;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

/**
* save download json
* @param list
*/
public void saveDLJson(ArrayList<INFO_DL> list){
if(null == list){
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- saveDLJson ArrayList<INFO_DL> is null");
return;
}
JSONArray jsonArray = new JSONArray();
JSONObject jsonObj = null;
INFO_DL infoItem = null;
for (int i = 0; i < list.size(); i++) {
jsonObj = new JSONObject();
infoItem = new INFO_DL();
infoItem = list.get(i);
try {
jsonObj.put("md5", infoItem.md5);
jsonObj.put("url", infoItem.url);
jsonObj.put("savePath", infoItem.savePath);
jsonObj.put("DLFlag", infoItem.DLFlag);
jsonObj.put("dlIndex", infoItem.dlIndex);
jsonObj.put("reTry", infoItem.reTry);
jsonObj.put("copyPath", infoItem.copyPath);
jsonObj.put("fileType", infoItem.fileType);
jsonArray.put(jsonObj);
} catch (JSONException e) {

e.printStackTrace();
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- saveDLJson has an exception");
return;
}
}
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- saveDLJson :"+jsonArray.toString());
Utils.setDLJson(jsonArray.toString());
}
}

同步帮助类

/**
* this class is responsible for sync picture include download and copy,
* @author WMB
*
*/
public class PicSyncHelper {
private static PicSyncHelper instance = null;
private ArrayList<INFO_DL> DLJsonList = new ArrayList<INFO_DL>(); // 同步所用list(DLFlag为false)
private ArrayList<INFO_DL> AllDLList = new ArrayList<INFO_DL>(); //  所有dlList不区分DLFlag(用于向硬盘中写下载数据)
private ArrayList<INFO_DL> UsingJsonList = new ArrayList<INFO_DL>(); // 屏保图片展示所用list
private String picCopyPath = ""; // 图片copy路径
private boolean isDownloadEnd = false;  // 下载完毕标志位
private boolean isCopyEnd = false;  // copy完毕标志位
private String filePath = "";
public static PicSyncHelper getInstance(){
if(null == instance){
instance = new PicSyncHelper();
}
return instance;
}
private PicSyncHelper(){
filePath = Common.getContext().getFilesDir().getPath();
}

private Handler mHandle = new Handler(){

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case PicCons.MESSAGE_DL:
case PicCons.MESSAGE_CP:
setScreenPath(true);
break;
case PicCons.MESSAGE_DL_PARTOK:
isDownloadEnd = true;
setScreenPath(false);
break;
case PicCons.MESSAGE_CP_PARTOK:
isCopyEnd = true;
setScreenPath(false);

default:
break;
}
}

};

/**
* 执行图片同步逻辑
*/
public void syncPicture(){
isDownloadEnd = false;
isCopyEnd = false;
if(DLJsonList == null || DLJsonList.size() <= 0){
initDLJson(); // 初始化下载List
}
if(DLJsonList == null || DLJsonList.size() <= 0){ // 下载List为空,不做处理,退出
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- syncPicture , DLJsonList is empty ,do nothing ,exist!");
return;
}
String usingJson = Utils.getUsingJson(); // 获取正在使用的Json信息
Utils.setScreenTimestamp(Utils.getCloudTimestamp()); //  保存本地同步时间戳
if(TextUtils.isEmpty(usingJson)){
// 全量下载
LogHelper.releaseLog(PicCons.SCREEN_TAG, "--begin All download , download size is:"+DLJsonList.size());
new Thread(new PicDownloadManager(DLJsonList, mHandle ,PicCons.MESSAGE_DL)).start();
}
else{ // 已存在则copy,不存在则下载
try {
JSONArray jsonArray = new JSONArray(usingJson);
if(null != UsingJsonList && UsingJsonList.size() == 0){
initUsingJsonList(jsonArray);
}
ArrayList<INFO_DL> dlList = new ArrayList<INFO_DL>();
final ArrayList<INFO_DL> cpList = new ArrayList<INFO_DL>();
INFO_DL Item = null;
for (int i = 0; i < DLJsonList.size(); i++) {
Item = DLJsonList.get(i);
if(picisExist(Item.md5)){ //加入复制
if(!TextUtils.isEmpty(picCopyPath)){
Item.copyPath = picCopyPath;
Item.savePath = getSavePath(picCopyPath);
cpList.add(Item);
}
}
else{ // 加入下载
dlList.add(Item);
}

}
if(dlList.size() > 0){
// 下载
if(cpList.size() > 0){
LogHelper.releaseLog(PicCons.SCREEN_TAG, "--begin Part of download , download size is:"+dlList.size());
new Thread(new PicDownloadManager(dlList,mHandle,PicCons.MESSAGE_DL_PARTOK)).start();
}
else{
LogHelper.releaseLog(PicCons.SCREEN_TAG, "--begin All download ,using json exist, download size is:"+dlList.size());
new Thread(new PicDownloadManager(dlList,mHandle,PicCons.MESSAGE_DL)).start();
}
}

if(cpList.size() > 0){
// 复制
if(dlList.size() > 0){
LogHelper.releaseLog(PicCons.SCREEN_TAG, "--begin Part copy, copy size is:"+cpList.size());
new Thread(new Runnable() {

@Override
public void run() {
copy(cpList, PicCons.MESSAGE_CP_PARTOK);
}
}).start();
}
else{
LogHelper.releaseLog(PicCons.SCREEN_TAG, "--begin All copy, copy size is:"+cpList.size());
new Thread(new Runnable() {

@Override
public void run() {
copy(cpList, PicCons.MESSAGE_CP);
}
}).start();
}
}
} catch (JSONException e) {

e.printStackTrace();
}
}
}

/**
* update download json info
* @param index
* @param data
*/
public void updateDLJson(int index, INFO_DL data){
if(null == AllDLList || AllDLList.size() == 0){
String DLJsonStr = Utils.getDLJson();
try {
JSONArray DLJsonArr = new JSONArray(DLJsonStr);
JSONObject updateItem = new JSONObject();
updateItem.put("md5", data.md5);
updateItem.put("url", data.url);
updateItem.put("savePath", data.savePath);
updateItem.put("DLFlag", data.DLFlag);
updateItem.put("dlIndex", data.dlIndex);
updateItem.put("reTry", data.reTry);
updateItem.put("copyPath", data.copyPath);
updateItem.put("fileType", data.fileType);
DLJsonArr.put(index, updateItem);
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- updateDLJson,DLJsonList is empty ,updata index : "+index+", jsonObj :"+updateItem.toString());
Utils.setDLJson(DLJsonArr.toString());
} catch (JSONException e) {
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- updateDLJson has an Exception");
e.printStackTrace();
return;
}
}
else{
if(index >= 0 && index < AllDLList.size()){
AllDLList.remove(index);
AllDLList.add(index, data);
saveDLJson(AllDLList);
}
}
}

/**
* save download json
* @param list
*/
public void saveDLJson(ArrayList<INFO_DL> list){
if(null == list){
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- saveDLJson ArrayList<INFO_DL> is null");
return;
}
JSONArray jsonArray = new JSONArray();
JSONObject jsonObj = null;
INFO_DL infoItem = null;
for (int i = 0; i < list.size(); i++) {
jsonObj = new JSONObject();
infoItem = new INFO_DL();
infoItem = list.get(i);
try {
jsonObj.put("md5", infoItem.md5);
jsonObj.put("url", infoItem.url);
jsonObj.put("savePath", infoItem.savePath);
jsonObj.put("DLFlag", infoItem.DLFlag);
jsonObj.put("dlIndex", infoItem.dlIndex);
jsonObj.put("reTry", infoItem.reTry);
jsonObj.put("copyPath", infoItem.copyPath);
jsonObj.put("fileType", infoItem.fileType);
jsonArray.put(jsonObj);
} catch (JSONException e) {

e.printStackTrace();
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- saveDLJson has an exception");
return;
}
}
DLJsonList = list;
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- saveDLJson :"+jsonArray.toString());
Utils.setDLJson(jsonArray.toString());
}

/**
* 获取下载路径,如果上次未下载完全,则还将图片下载到之前使用的目录中
* @return DLPath
*/
public String getDLPath(){
boolean isFullDownload = Utils.getFullDLFlag();
String usingPath = Utils.getScreenPath();
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- now screenPath is:"+usingPath);
String DLPath;
if(TextUtils.isEmpty(usingPath)){
DLPath = PicCons.SCREEN_PATH_A;
}
else{
if(isFullDownload){
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- isFUllDownload is true");
DLPath = PicCons.SCREEN_PATH_A.equals(usingPath)? PicCons.SCREEN_PATH_B : PicCons.SCREEN_PATH_A;
}
else{
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- isFUllDownload is false");
DLPath = PicCons.SCREEN_PATH_A.equals(usingPath)? PicCons.SCREEN_PATH_A : PicCons.SCREEN_PATH_B;
}
}
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- getDLPath : "+ filePath+DLPath);
return filePath+DLPath;
}

/**
* 判断图片是否在本地存在
* @param md5
* @return
*/
private boolean picisExist(String md5){
if(null == UsingJsonList || UsingJsonList.size() <= 0){
return false;
}
INFO_DL jsonItem = null;
for (int i = 0; i < UsingJsonList.size(); i++) {
jsonItem = UsingJsonList.get(i);
if(md5.equals(jsonItem.md5)){
picCopyPath = jsonItem.savePath;
return true;
}
}
return false;

}
/**
* 初始化下载使用Json信息
*/
private void initDLJson(){
String dlStr = Utils.getDLJson();
if(!TextUtils.isEmpty(dlStr)){

try {
JSONArray jsonArray = new JSONArray(dlStr);
if(null != jsonArray){
ArrayList<INFO_DL> allDLList = Utils.transJsonToList(jsonArray);
if(null != allDLList){
int size = allDLList.size();
INFO_DL item = null;
if(size > 0){
for (int i = 0; i < size; i++) {
item = allDLList.get(i);
AllDLList.add(item);
if(!item.DLFlag){ // 将下载或copy失败的加进来
DLJsonList.add(item);
}
}
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- initDLJson success , DLJsonList size:"+DLJsonList.size());
}

}
else{
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- initDLJson allDLList is null, so DLJsonList is empty");
}
}
} catch (Exception e) {
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- initDLJson has an Exception");
e.printStackTrace();
}

}
}

/**
* 初始化屏保图片使用Json信息
* @param jsonArray
*/
private void initUsingJsonList(JSONArray jsonArray) {
if(null == jsonArray){
return;
}
UsingJsonList = Utils.transJsonToList(jsonArray);
}

/**
* 根据图片拷贝路径,获得图片保存路径
* @param copyPath 图片拷贝路径
* @return 图片保存路径
*/
private String getSavePath(String copyPath){
String usingPath = Utils.getScreenPath();
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- getScreenPath --"+copyPath);
String newPath = "";
if(usingPath.contains(PicCons.SCREEN_PATH_A)){ // 从A到B
newPath = copyPath.replace(PicCons.SCREEN_PATH_A, PicCons.SCREEN_PATH_B);
}
else if(usingPath.contains(PicCons.SCREEN_PATH_B)){ // 从B到A
newPath = copyPath.replace(PicCons.SCREEN_PATH_B, PicCons.SCREEN_PATH_A);
}
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- getCopyFilePath --"+newPath);
return newPath;
}

//复制图片,利用管道流提升效率
private boolean copyAToB(String fileFrom , String fileTo){
File from = new File(fileFrom);
if(from.exists()){
File to = new File(fileTo);
if(!to.exists()){
try {
to.createNewFile();
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- copyAToB --create New file :" +to.getPath());
} catch (IOException e) {
e.printStackTrace();
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- copyAToB --create file has an Exception");
return false;
}
}
FileInputStream in = null;
FileOutputStream out = null;
FileChannel infc = null;
FileChannel outfc = null;
try {
in = new FileInputStream (from);
out = new FileOutputStream (to);
infc = in.getChannel();
outfc = out.getChannel();
//				int temp = 0;
//				while ((temp=in.read ())!=-1)
//				{
//					out.write (temp);
//				}
infc.transferTo(0, infc.size(), outfc);
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- copyAToB success from :"+ fileFrom+", to:"+fileTo);
return true;
} catch (Exception e) {
e.printStackTrace();
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- copyAToB has an Exception");
return false;
} finally {
try {
if(null != in){
in.close();
}
if(null != out){
out.close();
}
if(null != infc){
infc.close();
}
if(null != outfc){
outfc.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
else{
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- copyAToB fileFrom:"+fileFrom+" is not exists");
return false;
}

}

private void copy(ArrayList<INFO_DL> cpList ,int messageType){
if(null == cpList){
return;
}
createFolder();
INFO_DL Item = null;
for (int i = 0; i < cpList.size(); i++) {
Item = cpList.get(i);
boolean copysuccess = copyAToB(Item.copyPath, Item.savePath);
if(copysuccess){
if(Utils.MD5Check(Item.savePath, Item.md5)){
Item.DLFlag = true;
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- copy file MD5 check success , update Json Item");
updateDLJson(Item.dlIndex, Item);
}
}

}
mHandle.sendEmptyMessage(messageType);
}

/**
* 复制之前保证,PathA、PathB都存在
*/
private void createFolder(){
File pathA = new File(filePath+PicCons.SCREEN_PATH_A);
File pathB = new File(filePath+PicCons.SCREEN_PATH_B);
if(!pathA.exists()){
pathA.mkdirs();
}
if(!pathB.exists()){
pathB.mkdirs();
}
}

/**
* 修改fullDLFlag的值,是否完全下载
*/
private void setFullDLFlag(boolean fullDLFlag) {
Utils.setFullDLFlag(fullDLFlag);
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- setFullDLFlag: "+fullDLFlag);
}

/**
* 清空DLJsonList信息
*/
private void cleanDLJson(){
if(null != DLJsonList){
DLJsonList.clear();
}
}

/**
* 设置screenPath,图片成功数量大于约定上线,则设置,否则不设置
* @param setNow 是否直接设置,用于限制下载和copy都完成,则执行该逻辑
* @param isDownload
*/
private void setScreenPath(boolean setNow){
if(!setNow){
if(!isDownloadEnd || !isCopyEnd){
return;
}
}
cleanDLJson();
String DLJsonStr = Utils.getDLJson();
int dlSuccessSize = 0;
float dlTotalSize = 0;
if(!TextUtils.isEmpty(DLJsonStr)){
try {
JSONArray DLJsonArr= new JSONArray(DLJsonStr);
JSONObject DLJsonItem = null;
dlTotalSize = DLJsonArr.length();
for (int i = 0; i < dlTotalSize; i++) {
DLJsonItem = DLJsonArr.optJSONObject(i);
boolean dlSuccess = DLJsonItem.optBoolean("DLFlag");
if(dlSuccess){
dlSuccessSize++;
}
}

if(dlTotalSize > 0){
float DLSuccessRate = (float) dlSuccessSize / dlTotalSize;
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper --setScreenPath DLSuccessRate is:"+DLSuccessRate);
if(DLSuccessRate >= PicCons.SHOW_LIMIT){
String screenPath = getDLPath();
if(screenPath.contains(PicCons.SCREEN_PATH_A)){
Utils.setScreenPath(PicCons.SCREEN_PATH_A); // 设置显示目录为A
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper --setScreenPath PATH_A");
}
else{
Utils.setScreenPath(PicCons.SCREEN_PATH_B); // 设置显示目录为B
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper --setScreenPath PATH_B");
}
Utils.setUsingJson(DLJsonStr);  // 设置使用Json
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicSyncHelper -- setUsingJson :"+DLJsonStr);
}
if(DLSuccessRate == 1.0f){
setFullDLFlag(true);
}
else{
setFullDLFlag(false);
}
}

} catch (Exception e) {

}
}

}
}


其中主要方法为syncPicture,执行图片同步逻辑,启动线程下载、copy图片,完成后发送消息到Handler,执行setScreenPath方法。

Utils工具类

放置一些工具方法
public class Utils {

public static String getPicTypeByUrl(String url){
String picType = "";
if(TextUtils.isEmpty(url)){
return picType;
}
int lastPointIndex = url.lastIndexOf(".");
if(-1 == lastPointIndex){
return picType;
}

return url.substring(lastPointIndex, url.length());

}

public static boolean MD5Check(String filepath, String md5){
if(TextUtils.isEmpty(filepath) || TextUtils.isEmpty(md5)){
return false;
}
try {
String fileMd5 = MD5Util.getFileMD5String(new File(filepath));
return md5.equalsIgnoreCase(fileMd5);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}

/**
* JSONArray数组转为ArrayList
* @param dlFlag
* @param jsonArray
* @return
*/
public static ArrayList<INFO_DL> transJsonToList(JSONArray jsonArray){
if(null == jsonArray){
return null;
}
ArrayList<INFO_DL> jsonList = new ArrayList<INFO_DL>();
INFO_DL infoItem = null;
JSONObject jsonObj = null;
for (int i = 0; i < jsonArray.length(); i++) {
infoItem = new INFO_DL();
jsonObj = jsonArray.optJSONObject(i);
infoItem.md5 = jsonObj.optString("md5");
infoItem.url = jsonObj.optString("url");
infoItem.DLFlag = jsonObj.optBoolean("DLFlag");
infoItem.savePath = jsonObj.optString("savePath");
infoItem.dlIndex = jsonObj.optInt("dlIndex");
infoItem.reTry = jsonObj.optInt("reTry");
infoItem.copyPath = jsonObj.optString("copyPath");
infoItem.fileType = jsonObj.optString("fileType");
jsonList.add(infoItem);
}
return jsonList;

}

/**
* 根据固件版本获取序列号
* @param version
* @return
*/
public static String getServiceByVersion(String version){
String service = "";
if(TextUtils.isEmpty(version)){
return service;
}
int index = version.indexOf("-");
if(-1 == index){
return service;
}

return version.substring(0, index);

}

/**
* 存云端时间
*
* @param cloudTimestamp
*/
public static void setCloudTimestamp(String cloudTimestamp) {
saveGlobalData(Define.KEY_SCREEN_CLOUDTIMESTAMP, cloudTimestamp);
}

/**
* 获取云端时间戳
*
* @return 云端时间戳
*/
public static String getCloudTimestamp() {
String cloudTimestamp = getGlobalData(Define.KEY_SCREEN_CLOUDTIMESTAMP);
if (!TextUtils.isEmpty(cloudTimestamp)) {
return cloudTimestamp;
}
return "";
}

/**
* 存屏保同步的时间戳,用于和云端时间戳比较
*
* @param timestamp
*/
public static void setScreenTimestamp(String timestamp) {
saveGlobalData(Define.KEY_SCREEN_TIMESTAMP, timestamp);
}

/**
* 获取屏保同步时间戳
*
* @return 上次同步时间,第一次为""
*/
public static String getScreenTimestamp() {
String timestamp = getGlobalData(Define.KEY_SCREEN_TIMESTAMP);
if (!TextUtils.isEmpty(timestamp)) {
return timestamp;
}
return "";
}

/**
* 存当前屏保正在使用的图片目录
*
* @param screenUsingPath
*            正在使用的图片目录
*/
public static void setScreenPath(String screenUsingPath) {
saveGlobalData(Define.KEY_SCREEN_USINGPATH, screenUsingPath);
}

/**
* 获取当前屏保正在使用的图片目录
*
* @return 屏保正在使用的目录,第一次为"",第一次进入屏保后该值应设置为PathA
*/
public static String getScreenPath() {
String screenPath = getGlobalData(Define.KEY_SCREEN_USINGPATH);
if (!TextUtils.isEmpty(screenPath)) {
return screenPath;
}
return "";
}

/**
* 存屏保当前使用Json
*
* @param usingJson
*/
public static void setUsingJson(String usingJson) {
saveGlobalData(Define.KEY_SCREEN_JSONUSING, usingJson);
}

/**
* 获取屏保当前使用Json
*
* @return 当前使用的Json文件信息,第一次为""
*/
public static String getUsingJson() {
String usingJson = getGlobalData(Define.KEY_SCREEN_JSONUSING);
if (!TextUtils.isEmpty(usingJson)) {
return usingJson;
}
return "";
}

/**
* 存下载图片使用Json
*
* @param DLJson
*/
public static void setDLJson(String DLJson) {
saveGlobalData(Define.KEY_SCREEN_JSONDL, DLJson);
}

/**
* 获取下载图片使用Json
*
* @return 下载图片用到的Json文件
*/
public static String getDLJson() {
String DLJson = getGlobalData(Define.KEY_SCREEN_JSONDL);
if (!TextUtils.isEmpty(DLJson)) {
return DLJson;
}
return "";
}

/**
* 存图片是否完全下载成功
*
* @param fullDL
*            true: 100%下载 ,false:未完全下载
*/
public static void setFullDLFlag(boolean fullDL) {
String fullDLFlag = "0";
if (fullDL) {
fullDLFlag = "1";
}
saveGlobalData(Define.KEY_SCREEN_FULLDL, fullDLFlag);

}

/**
* 获取图片是否完全下载成功
*
* @return true:完全下载,false:未完全下载
*/
public static boolean getFullDLFlag() {
String fullDLFlag = getGlobalData(Define.KEY_SCREEN_FULLDL);
if (!TextUtils.isEmpty(fullDLFlag) && "1".equals(fullDLFlag)) {
return true;
}
return false;
}

private static void saveGlobalData(String key, String value){
Common.getGlobalData().setGlobalData(key, value);
}

private static String getGlobalData(String key){
return Common.getGlobalData().getGlobalData(key);
}

}

下载管理类

public class PicDownloadManager implements Runnable{
private int dlIndex = 0;
private INFO_DL dlInfo = null;
private String dlPath = "";
private Handler mHandler = null;
private int messageType = 1; // 消息类型,用于区分是否全量下载(无copy)
private ArrayList<INFO_DL> dlList = new ArrayList<INFO_DL>();

/**
* 下载管理类,负责从云端下载图片,包括下载成功后Md5Check,以及下载失败后最多3次重试
* @param dlList 下载List
* @param handler 下载完成后发送消息到主线程
* @param messageType 发送消息类型(包括全量下载、部分下载)
*/
public PicDownloadManager(ArrayList<INFO_DL> dlList, Handler handler, int messageType){
this.messageType = messageType;
this.dlList = dlList;
mHandler = handler;
initDLPath();
}
/**
* 初始化下载路径(绝对路径/data/data../PathA或PathB)
*/
private void initDLPath(){
dlPath = PicSyncHelper.getInstance().getDLPath();
}

public void dlStart(){
dlInfo = dlList.get(dlIndex);
PicDownloader pic = new  PicDownloader(dlPath ,dlInfo ,mDLListener);
pic.download();
}

@Override
public void run() {
dlStart();
}

/**
* 下载监听,用于响应下载成功、下载失败以后的处理
*/
private IDLListener mDLListener = new IDLListener() {

@Override
public void onFinish(INFO_DL info) {
// md5 check
// error retry,success dl next
if(Utils.MD5Check(info.savePath, info.md5)){ // check success
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicDownloadManager -- onFinish Md5check success");
info.DLFlag = true;
PicSyncHelper.getInstance().updateDLJson(info.dlIndex, info); // update dlJson
if(dlIndex < dlList.size() - 1){
dlIndex++;
dlInfo = dlList.get(dlIndex);
PicDownloader pic = new  PicDownloader(dlPath, dlInfo, mDLListener);
pic.download();
}
else{
mHandler.sendEmptyMessage(messageType);
}
}
else{ // download error
dealError(info);
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicDownloadManager -- onFinish Md5check error");
}
}

@Override
public void onError(INFO_DL info) {
// retry limit , download next
dealError(info);
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicDownloadManager -- onError");
}
};

/**
* 处理下载失败的情况(包括下载成功但MD5 check失败的情况)
* @param info
*/
private void dealError(INFO_DL info){

if(info.reTry < PicCons.MAX_RETRY){
info.reTry ++;
PicDownloader pic = new  PicDownloader(dlPath, info, mDLListener);
pic.download();
}
else{
if(dlIndex < dlList.size() - 1){
dlIndex++;
dlInfo = dlList.get(dlIndex);
PicDownloader pic = new  PicDownloader(dlPath, dlInfo, mDLListener);
pic.download();
}
else{
mHandler.sendEmptyMessage(messageType);
}
}
}

public interface IDLListener {
void onError(INFO_DL info);
void onFinish(INFO_DL info);
}

}

}

下载类

public class PicDownloader{
private String savePath;
private INFO_DL DLInfo;
private IDLListener listener;
private String picName;

/**
* 执行图片下载类
* @param savePath 图片保存的路径
* @param DLInfo  下载封装信息体
* @param listener 下载状态回调
*/
public PicDownloader(String savePath,INFO_DL DLInfo,IDLListener listener){
this.savePath = savePath;
this.DLInfo = DLInfo;
this.listener = listener;
picName = DLInfo.md5+DLInfo.fileType;
}
/**
* 开始下载
*/
public void download() {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(DLInfo.url).openConnection();
conn.setConnectTimeout(PicCons.DEFAULT_TIMEOUT);
conn.setReadTimeout(PicCons.DEFAULT_TIMEOUT);
addRequestHeaders(conn);
final int code = conn.getResponseCode();
LogHelper.releaseLog(PicCons.SCREEN_TAG,"PicDownloader -- run getResponseCode : " + code);
if (PicCons.HTTP_OK == code) {
dlInit(conn, code);
}
else{
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicDownloader -- run listener.onError");
if(null != listener){
listener.onError(DLInfo);
}
return;
}
} catch (Exception e) {
e.printStackTrace();
if(null != listener){
listener.onError(DLInfo);
}
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicDownloader -- run has an Exception");

} finally {
if (null != conn)
conn.disconnect();
}

}

private void dlInit(HttpURLConnection conn, int code){
if (!createFile(savePath, picName)){
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicDownloader -- dlInit Can not create file:"+savePath+"picName");
if(null != listener){
listener.onError(DLInfo);
}
return;
}
dlData(conn);
}

private void dlData(HttpURLConnection conn){
InputStream is = null;
FileOutputStream fos = null;
try {
is = conn.getInputStream();
fos = new FileOutputStream(new File(savePath, picName));
byte [] b = new byte[4096];
int len;
while((len = is.read(b)) != -1){
fos.write(b, 0, len);
}
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicDownloader -- dlData download finish : "+savePath+"-"+DLInfo.md5);
if(null != listener){
listener.onFinish(DLInfo);
}

} catch (IOException e) {
e.printStackTrace();
if(null != listener){
listener.onError(DLInfo);
}
LogHelper.releaseLog(PicCons.SCREEN_TAG, "PicDownloader -- dlData has an Exception");
return;
} finally {
try {
if(null != is){
is.close();
}
if(null != fos){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

private synchronized boolean createFile(String path, String fileName) {
boolean hasFile = false;
try {
File dir = new File(path);
boolean hasDir = dir.exists() || dir.mkdirs();
if (hasDir) {
File file = new File(dir, fileName);
hasFile = file.exists() || file.createNewFile();
DLInfo.savePath = file.getPath();
}
} catch (IOException e) {
e.printStackTrace();
}
return hasFile;
}

private void addRequestHeaders(HttpURLConnection conn) {
conn.addRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg," +
"application/x-shockwave-flash, application/xaml+xml," +
"application/vnd.ms-xpsdocument, application/x-ms-xbap," +
"application/x-ms-application, application/vnd.ms-excel," +
"application/vnd.ms-powerpoint, application/msword, */*");
conn.addRequestProperty("Charset", "UTF-8");
conn.addRequestProperty("Connection", "Keep-Alive");
conn.addRequestProperty("Accept-Encoding", "identity");

}

}


上面就是图片同步的整个过程,欢迎大家讨论。

谢谢。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: