最近学习研究了下用http进行大文件上传:
经过不断修复优化,功能实现如下: 1.上传大文件; 2.实现多文件同时上传; 3.实现文件断点续传; 4.提供上传回调,显示上传速度与进度; 5.多线程上传,使用线程池进行管理; 6.上传失败保存现场,下回继续上传; ……..
直接贴代码,如有疑问请留言,参与讨论;
有三个核心类:ResumableUploadUtil ,UpLoadFileInfo,UploadTimerTask
ResumableUploadUtil 用于完成上传核心逻辑:
package upload;
import android.os.Handler;
import upload.UpLoadFileInfo;
import upload.ConstantValue;
import upload.MyApplicationLike;
import upload.ActivityStack;
import upload.Logger;
import upload.StringUtil;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.concurrent.Executors;
/**
* Created by LiKang on 2016/12/22 15:15.
* email:15034671952@163.com
*/
public class ResumableUploadUtil {
private final String Tag =
"ResumableUploadUtil";
private final String BOUNDARY =
"----androidUploadBinBoundary";
private Handler handler;
/**
* 默认分段大小
*/
public final static long defaultChunkSize =
1024 *
1024 *
3 /
2;
/**
* 默认缓冲区大小
*/
public final static int defaultBufferSize =
1024 *
4;
/**
* 默认并发上传线程数
*/
public final static int defalutConcurrentThreadsNum =
3;
private int concurrentThreadsNum = ResumableUploadUtil.defalutConcurrentThreadsNum;
public ResumableUploadUtil() {
this.handler =
new Handler();
}
/**
* 上传 准备;
*/
private void upLoadPrepare(UpLoadFileInfo fileInfo) {
computeChunkNums(fileInfo);
computeEachThreadChunkNum(fileInfo);
}
/**
* 计算分几片段;
*/
private void computeChunkNums(UpLoadFileInfo fileInfo) {
long tempLastChunkSize = fileInfo.fileSize % defaultChunkSize;
fileInfo.totalChunks = (
int) (fileInfo.fileSize / defaultChunkSize);
if (tempLastChunkSize !=
0) {
fileInfo.totalChunks +=
1;
}
Logger.d(Tag,
"totalChunks:" + fileInfo.totalChunks);
}
/**
* 设置 工作线程信息
*/
private void computeEachThreadChunkNum(UpLoadFileInfo fileInfo) {
int eachThreadChunkNum = fileInfo.totalChunks / concurrentThreadsNum;
int remainedChunkNum = fileInfo.totalChunks % concurrentThreadsNum;
for (
int threadIndex =
0; threadIndex < concurrentThreadsNum; threadIndex++) {
HashMap<String, Integer> perThreadInfo =
new HashMap<>();
if (remainedChunkNum > threadIndex) {
perThreadInfo.put(
"eachThreadChunkNum", eachThreadChunkNum +
1);
perThreadInfo.put(
"endThreadChunkIndex", threadIndex * (eachThreadChunkNum +
1) + eachThreadChunkNum);
perThreadInfo.put(
"curThreadChunkIndex", threadIndex * (eachThreadChunkNum +
1));
perThreadInfo.put(
"startThreadChunkIndex", threadIndex * (eachThreadChunkNum +
1));
}
else {
perThreadInfo.put(
"eachThreadChunkNum", eachThreadChunkNum);
perThreadInfo.put(
"endThreadChunkIndex", threadIndex * eachThreadChunkNum + eachThreadChunkNum -
1 + remainedChunkNum);
perThreadInfo.put(
"curThreadChunkIndex", threadIndex * eachThreadChunkNum + remainedChunkNum);
perThreadInfo.put(
"startThreadChunkIndex", threadIndex * eachThreadChunkNum + remainedChunkNum);
}
perThreadInfo.put(
"threadId", threadIndex);
fileInfo.threadInfo.add(perThreadInfo);
}
Logger.d(Tag,
"fileInfo.threadInfo:" + fileInfo.threadInfo);
}
/**
* 获取当前片段大小
*
* @return
*/
private long getCurrentChunkSize(
int curThreadChunkIndex, UpLoadFileInfo fileInfo) {
long tempLastChunkSize = fileInfo.fileSize % defaultChunkSize;
if (tempLastChunkSize !=
0) {
if (curThreadChunkIndex == fileInfo.totalChunks -
1) {
return tempLastChunkSize;
}
else {
return defaultChunkSize;
}
}
else {
return defaultChunkSize;
}
}
/**
* 重新计算当前上传大小;
*
* @return
*/
private void recomputeHasUploadSize(UpLoadFileInfo fileInfo) {
fileInfo.hasUploadSize =
0;
fileInfo.hasUploadSizeBeforeOneSec =
0;
for (
int threadIndex =
0; threadIndex < concurrentThreadsNum; threadIndex++) {
HashMap<String, Integer> perThreadInfo = fileInfo.threadInfo.get(threadIndex);
int curThreadChunkIndex = perThreadInfo.get(
"curThreadChunkIndex");
int startThreadChunkIndex = perThreadInfo.get(
"startThreadChunkIndex");
for (
int tempIndex =
0; tempIndex < curThreadChunkIndex - startThreadChunkIndex; tempIndex++) {
fileInfo.hasUploadSize += getCurrentChunkSize(tempIndex, fileInfo);
}
}
}
/**
* 开始或继续上传;
*
* @param fileInfo
*/
public void startUpload(
final UpLoadFileInfo fileInfo) {
if (fileInfo.uploadStatus == UploadStatus.NOTSTART) {
upLoadPrepare(fileInfo);
}
else {
recomputeHasUploadSize(fileInfo);
}
fileInfo.uploadStatus = ResumableUploadUtil.UploadStatus.UPLOADING;
fileInfo.fixedThreadPool = Executors.newFixedThreadPool(concurrentThreadsNum);
fileInfo.isBecauseDoBackgroundPause =
false;
startCountTime(fileInfo);
if (fileInfo.resumableUploadListener !=
null) {
fileInfo.resumableUploadListener.onUpLoadStart(fileInfo);
}
for (
int threadIndex =
0; threadIndex < concurrentThreadsNum; threadIndex++) {
HashMap<String, Integer> threadInfotemp = fileInfo.threadInfo.get(threadIndex);
Integer eachThreadChunkNum = threadInfotemp.get(
"eachThreadChunkNum");
Integer curThreadChunkIndex = threadInfotemp.get(
"curThreadChunkIndex");
Integer endThreadChunkIndex = threadInfotemp.get(
"endThreadChunkIndex");
Integer threadId = threadInfotemp.get(
"threadId");
Logger.e(Tag,
"threadId:" + threadId +
"," +
"eachThreadChunkNum:" + eachThreadChunkNum +
"," +
"curThreadChunkIndex:" + curThreadChunkIndex +
"endThreadChunkIndex:" + endThreadChunkIndex);
if (eachThreadChunkNum !=
0) {
doUpload(threadIndex, fileInfo);
}
}
}
/**
* 上传暂停;
*
* @param becauseDoBackgroundPause 是否因为后台运行停止上传;
* @param fileInfo
*/
public void uploadPause(
boolean becauseDoBackgroundPause,
final UpLoadFileInfo fileInfo) {
fileInfo.uploadStatus = ResumableUploadUtil.UploadStatus.PAUSE;
fileInfo.isBecauseDoBackgroundPause = becauseDoBackgroundPause;
stopCountTime(fileInfo);
saveUploadFileInfo(fileInfo);
if (fileInfo.resumableUploadListener !=
null) {
handler.post(
new Runnable() {
@Override
public void run() {
fileInfo.resumableUploadListener.onUpLoadPause(fileInfo);
}
});
}
if (fileInfo.fixedThreadPool !=
null) {
fileInfo.fixedThreadPool.shutdownNow();
fileInfo.fixedThreadPool =
null;
}
}
/**
* 上传错误
*
* @param e 异常类别
* @param fileInfo
*/
public synchronized void uploadError(
final Exception e,
final UpLoadFileInfo fileInfo) {
if (fileInfo.uploadStatus != UploadStatus.UPLOADING) {
return;
}
Logger.d(Tag,
"uploadError");
fileInfo.uploadStatus = ResumableUploadUtil.UploadStatus.ERROR;
if (fileInfo.resumableUploadListener !=
null) {
handler.post(
new Runnable() {
@Override
public void run() {
fileInfo.resumableUploadListener.onUpLoadError(e, fileInfo);
}
});
}
stopCountTime(fileInfo);
saveUploadFileInfo(fileInfo);
if (fileInfo.fixedThreadPool !=
null) {
fileInfo.fixedThreadPool.shutdownNow();
fileInfo.fixedThreadPool =
null;
}
}
/**
* 上传成功
*
* @param fileInfo
* @param url
*/
private void uploadSuccess(
final UpLoadFileInfo fileInfo, String url) {
Logger.d(Tag,
"任务上传成功!!!");
fileInfo.uploadStatus = UploadStatus.SUCCESS;
removeUploadFileInfo(fileInfo);
stopCountTime(fileInfo);
fileInfo.fileUrl = url;
if (fileInfo.resumableUploadListener !=
null) {
handler.post(
new Runnable() {
@Override
public void run() {
fileInfo.resumableUploadListener.onUpLoadSuccess(fileInfo);
}
});
}
if (fileInfo.fixedThreadPool !=
null) {
fileInfo.fixedThreadPool.shutdownNow();
fileInfo.fixedThreadPool =
null;
}
}
/**
* 保存上传文件记录
*
* @param fileInfo
*/
public void saveUploadFileInfo(UpLoadFileInfo fileInfo) {
String cacheFileExtension =
"";
if (fileInfo.fileType.equals(ConstantValue.FILETYPE_VIDEO)) {
cacheFileExtension = ConstantValue.cacheVideoExtension;
}
else if (fileInfo.fileType.equals(ConstantValue.FILETYPE_DOC)) {
cacheFileExtension = ConstantValue.cacheDocExtension;
}
fileInfo.cacheUploadFilePath = CacheUploadInfo.saveUploadInfoFile + File.separator
+ fileInfo.fileType + fileInfo.uploadFileId +
"." + cacheFileExtension;
Logger.d(
"cacheUploadFilePath", fileInfo.cacheUploadFilePath);
CacheUploadInfo.writeObjectToFile(fileInfo, fileInfo.cacheUploadFilePath);
}
/**
* 删除文件上传记录
*
* @param fileInfo
*/
public void removeUploadFileInfo(UpLoadFileInfo fileInfo) {
if (!StringUtil.isBlank(fileInfo.cacheUploadFilePath)) {
File cacheUploadfile =
new File(fileInfo.cacheUploadFilePath);
if (cacheUploadfile.exists()) {
cacheUploadfile.delete();
}
}
}
/**
* 开启一个任务上传;
*
* @param threadIndex
* @param fileInfo
*/
private void doUpload(
final int threadIndex,
final UpLoadFileInfo fileInfo) {
if (fileInfo.fixedThreadPool ==
null)
return;
if (!fileInfo.fixedThreadPool.isShutdown()) {
fileInfo.fixedThreadPool.execute(
new Runnable() {
@Override
public void run() {
try {
byte[] headerInfo = buildHeaderInfo(threadIndex, fileInfo);
byte[] endInfo = (
"\r\n--" + BOUNDARY +
"--\r\n").getBytes(
"UTF-8");
HttpURLConnection conn = initHttpConnection(fileInfo.remoteUrl);
OutputStream out = conn.getOutputStream();
out.write(headerInfo);
writeToServer(threadIndex, conn, out, endInfo, fileInfo);
}
catch (Exception e) {
e.printStackTrace();
uploadError(e, fileInfo);
}
}
});
}
}
/**
* 构建上传参数;
*
* @param threadIndex
* @param fileInfo
* @return
* @throws UnsupportedEncodingException
*/
private byte[]
buildHeaderInfo(
int threadIndex, UpLoadFileInfo fileInfo)
throws UnsupportedEncodingException {
HashMap<String, String> params =
new HashMap<>();
params.put(
"cloudUserGUID", fileInfo.comParams.get(
"cloudUserGUID"));
params.put(
"notifyUrl", fileInfo.uploadSuccessCallback);
params.put(
"fileType", fileInfo.fileType);
params.put(
"storageServerGUID", fileInfo.storageServerGUID);
params.put(
"resumableType",
"application/x-zip-compressed");
params.put(
"resumableTotalSize", fileInfo.fileSize +
"");
params.put(
"resumableIdentifier", fileInfo.fileSize +
"-" + fileInfo.fileName +
"");
params.put(
"resumableFilename", fileInfo.fileName +
"");
params.put(
"resumableRelativePath", fileInfo.filePath);
params.put(
"resumableChunkSize", defaultChunkSize +
"");
params.put(
"resumableTotalChunks", fileInfo.totalChunks +
"");
HashMap<String, Integer> perThreadInfo = fileInfo.threadInfo.get(threadIndex);
int curThreadChunkIndex = perThreadInfo.get(
"curThreadChunkIndex");
params.put(
"resumableCurrentChunkSize", getCurrentChunkSize(curThreadChunkIndex, fileInfo) +
"");
params.put(
"resumableChunkNumber", curThreadChunkIndex +
1 +
"");
StringBuilder sb =
new StringBuilder();
for (String key : params.keySet()) {
sb.append(
"--" + BOUNDARY +
"\r\n");
sb.append(
"Content-Disposition: form-data; name=\"" + key +
"\""
+
"\r\n");
sb.append(
"\r\n");
sb.append(params.get(key) +
"\r\n");
}
sb.append(
"--" + BOUNDARY +
"\r\n");
sb.append(
"Content-Disposition: form-data; name=\"file\"; filename=\"" + fileInfo.fileName +
"\"" +
"\r\n");
sb.append(
"Content-Type: application/octet-stream" +
"\r\n");
sb.append(
"\r\n");
Logger.d(
"buildHeaderInfo",
"threadIndex:" + threadIndex +
",resumableTotalSize:"
+ fileInfo.fileSize +
",resumableTotalChunks:"
+ fileInfo.totalChunks +
",resumableCurrentChunkSize:"
+ getCurrentChunkSize(curThreadChunkIndex, fileInfo) +
",resumableChunkNumber" + (curThreadChunkIndex +
1) +
"");
byte[] haderInfoBytes = sb.toString().getBytes(
"UTF-8");
params =
null;
sb =
null;
return haderInfoBytes;
}
/**
* 初始化 http连接
*
* @param url
* @return
* @throws IOException
*/
private HttpURLConnection
initHttpConnection(URL url)
throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(
"POST");
conn.setRequestProperty(
"Content-Type",
"multipart/form-data; boundary=" + BOUNDARY);
conn.setConnectTimeout(
30 *
1000);
conn.setRequestProperty(
"Connection",
"Keep-Alive");
conn.setRequestProperty(
"Charset",
"UTF-8");
conn.setDoInput(
true);
conn.setUseCaches(
false);
conn.setDoOutput(
true);
return conn;
}
public void writeToServer(
int threadIndex, HttpURLConnection conn, OutputStream out,
byte[] endInfo,
final UpLoadFileInfo fileInfo)
throws Exception {
RandomAccessFile raf =
new RandomAccessFile(
new File(fileInfo.filePath),
"r");
float filesize = fileInfo.fileSize;
HashMap<String, Integer> perThreadInfo = fileInfo.threadInfo.get(threadIndex);
int curThreadChunkIndex = perThreadInfo.get(
"curThreadChunkIndex");
raf.seek(defaultChunkSize * curThreadChunkIndex);
byte b[] =
new byte[defaultBufferSize];
int n =
0;
long readLength =
0;
while (readLength < getCurrentChunkSize(curThreadChunkIndex, fileInfo)) {
boolean runningOnBackground = ActivityStack.isRunningOnBackground(MyApplicationLike.getContext());
if (runningOnBackground) {
uploadPause(
true, fileInfo);
}
if (fileInfo.uploadStatus != UploadStatus.UPLOADING) {
return;
}
n = raf.read(b,
0, defaultBufferSize);
out.write(b,
0, n);
readLength += n;
fileInfo.hasUploadSize += n;
fileInfo.updateTextProgress();
fileInfo.uploadProgress = (fileInfo.hasUploadSize / filesize) *
100;
Logger.d(Tag,
"进度:" + fileInfo.uploadProgress +
"%" +
",hasUploadSize:" + fileInfo.hasUploadSize +
",filesize:" + filesize);
if (fileInfo.resumableUploadListener !=
null) {
handler.post(
new Runnable() {
@Override
public void run() {
if (fileInfo.uploadStatus == UploadStatus.UPLOADING) {
fileInfo.resumableUploadListener.onUpLoading(fileInfo);
}
}
});
}
}
out.write(endInfo);
out.close();
raf.close();
raf =
null;
b =
null;
handleWriterResult(threadIndex, conn, fileInfo);
}
/**
* 处理每一片上传结果
*
* @param threadIndex
* @param conn
* @param fileInfo
* @throws Exception
*/
private void handleWriterResult(
int threadIndex, HttpURLConnection conn,
final UpLoadFileInfo fileInfo)
throws Exception {
final String responseMsg = getResponseMsg(conn);
Logger.d(Tag,
"responseMsg:" + responseMsg);
HashMap<String, Integer> perThreadInfo = fileInfo.threadInfo.get(threadIndex);
int curThreadChunkIndex = perThreadInfo.get(
"curThreadChunkIndex");
int eachThreadChunkNum = perThreadInfo.get(
"eachThreadChunkNum");
int startThreadChunkIndex = perThreadInfo.get(
"startThreadChunkIndex");
int endThreadChunkIndex = perThreadInfo.get(
"endThreadChunkIndex");
if (curThreadChunkIndex != endThreadChunkIndex) {
if (conn.getResponseCode() ==
200) {
Logger.d(
"handle2WriterResult",
"handleWriterResult: " +
",threadIndex:" + threadIndex +
" ,CurrentChunkSize:" + getCurrentChunkSize(curThreadChunkIndex, fileInfo) +
",curThreadChunkIndex:" + curThreadChunkIndex +
",eachThreadChunkNum:" + eachThreadChunkNum +
",startThreadChunkIndex:" + startThreadChunkIndex +
",endThreadChunkIndex:" + endThreadChunkIndex +
",totalChunks:" + fileInfo.totalChunks);
Logger.d(Tag,
"工作线程:" + threadIndex +
"上传成功" +
",curThreadChunkIndex:" + curThreadChunkIndex);
if (curThreadChunkIndex < endThreadChunkIndex) {
curThreadChunkIndex +=
1;
perThreadInfo.put(
"curThreadChunkIndex", curThreadChunkIndex);
}
doUpload(threadIndex, fileInfo);
Logger.d(Tag,
"继续上传!!!");
}
else {
uploadError(
null, fileInfo);
}
}
else {
if (conn.getResponseCode() ==
200) {
Logger.d(
"handle2WriterResult",
"handleWriterResult: " +
",threadIndex:" + threadIndex +
" ,CurrentChunkSize:" + getCurrentChunkSize(curThreadChunkIndex, fileInfo) +
",curThreadChunkIndex:" + curThreadChunkIndex +
",eachThreadChunkNum:" + eachThreadChunkNum +
",startThreadChunkIndex:" + startThreadChunkIndex +
",endThreadChunkIndex:" + endThreadChunkIndex +
",totalChunks:" + fileInfo.totalChunks);
Logger.d(Tag,
"工作线程:" + threadIndex +
"上传成功最后一段!!!");
if (curThreadChunkIndex < endThreadChunkIndex) {
curThreadChunkIndex +=
1;
perThreadInfo.put(
"curThreadChunkIndex", curThreadChunkIndex);
}
if (!StringUtil.isBlank(responseMsg)) {
JSONObject object =
new JSONObject(responseMsg);
final String url = String.valueOf(object.get(
"data"));
if (!StringUtil.isBlank(url)) {
uploadSuccess(fileInfo, url);
}
object =
null;
}
}
else {
uploadError(
null, fileInfo);
}
}
}
/**
* 获取到每一片 上传后结果
*
* @param conn
* @return
* @throws IOException
*/
private String
getResponseMsg(HttpURLConnection conn)
throws IOException {
StringBuilder sbResponse =
new StringBuilder();
BufferedReader in =
new BufferedReader(
new InputStreamReader(conn
.getInputStream(),
"UTF-8"));
String inputLine;
while ((inputLine = in.readLine()) !=
null) {
sbResponse.append(inputLine);
}
in.close();
String responseMsg = sbResponse.toString();
in =
null;
sbResponse =
null;
return responseMsg;
}
public void startCountTime(UpLoadFileInfo fileInfo) {
if (fileInfo.timerTask ==
null) {
fileInfo.timerTask =
new UploadTimerTask(fileInfo);
}
fileInfo.timerTask.start();
}
public void stopCountTime(UpLoadFileInfo fileInfo) {
if (fileInfo.timerTask !=
null) {
fileInfo.timerTask.stop();
}
}
public enum UploadStatus {
UPLOADING, SUCCESS, PAUSE, NOTSTART, ERROR
}
public interface ResumableUploadListener {
void onUpLoading(UpLoadFileInfo fileInfo);
void onUpLoadSuccess(UpLoadFileInfo fileInfo);
void onUpLoadError(Exception e, UpLoadFileInfo fileInfo);
void onUpLoadStart(UpLoadFileInfo fileInfo);
void onUpLoadPause(UpLoadFileInfo fileInfo);
}
public void setResumableUploadListener(ResumableUploadUtil.ResumableUploadListener listener, UpLoadFileInfo fileInfo) {
fileInfo.resumableUploadListener = listener;
}
}
UpLoadFileInfo 用于保存上传记录:
package upload;
import upload.ResumableUploadUtil;
import upload.UploadTimerTask;
import upload.StringUtil;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import static upload.StringUtil.getDataSize;
public class UpLoadFileInfo implements Serializable {
public URL remoteUrl;
public String fileUrl;
public String fileName;
public String filePath;
public String cacheUploadFilePath;
public long fileSize;
public long hasUploadSize;
public long hasUploadSizeBeforeOneSec;
public long ModifiedDate;
public long dbId;
public float uploadProgress;
public String uploadFileId;
public int recLen =
0;
public HashMap<String, String> comParams;
public String rootDir;
public String storageServerGUID;
public String uploadSuccessCallback;
public String fileType;
public String extension;
public String textProgress = updateTextProgress();
public String uploadSpeed = updateUploadSpeed();
public boolean isBecauseDoBackgroundPause =
false;
public int totalChunks =
0;
public transient UploadTimerTask timerTask;
public transient ExecutorService fixedThreadPool;
/**
* 上传监听
*/
public transient ResumableUploadUtil.ResumableUploadListener resumableUploadListener;
/**
* 上传状态
*/
public ResumableUploadUtil.UploadStatus uploadStatus = ResumableUploadUtil.UploadStatus.NOTSTART;
/**
* 工作线程信息
*/
public List<HashMap<String, Integer>> threadInfo =
new ArrayList<>();
public String
updateTextProgress() {
return textProgress = StringUtil.getDataSize(hasUploadSize) +
"/" + StringUtil.getDataSize(fileSize);
}
public String
updateUploadSpeed() {
return uploadSpeed = getDataSize(hasUploadSize - hasUploadSizeBeforeOneSec) +
"/s";
}
@Override
public String
toString() {
return "UpLoadFileInfo{" +
"UploadTimerTask=" + timerTask +
", remoteUrl=" + remoteUrl +
", fileUrl='" + fileUrl +
'\'' +
", fileName='" + fileName +
'\'' +
", filePath='" + filePath +
'\'' +
", cacheUploadFilePath='" + cacheUploadFilePath +
'\'' +
", fileSize=" + fileSize +
", hasUploadSize=" + hasUploadSize +
", ModifiedDate=" + ModifiedDate +
", dbId=" + dbId +
", uploadProgress=" + uploadProgress +
", uploadFileId=" + uploadFileId +
", recLen=" + recLen +
", comParams=" + comParams +
", rootDir='" + rootDir +
'\'' +
", storageServerGUID='" + storageServerGUID +
'\'' +
", uploadSuccessCallback='" + uploadSuccessCallback +
'\'' +
", fileType='" + fileType +
'\'' +
", extension='" + extension +
'\'' +
", textProgress='" + textProgress +
'\'' +
", uploadSpeed='" + uploadSpeed +
'\'' +
", fixedThreadPool=" + fixedThreadPool +
", resumableUploadListener=" + resumableUploadListener +
", uploadStatus=" + uploadStatus +
", totalChunks=" + totalChunks +
", isBecauseDoBackgroundPause=" + isBecauseDoBackgroundPause +
", threadInfo=" + threadInfo +
'}';
}
}
UploadTimerTask 用于计时,计算上传速度:
package upload;
import android.os.SystemClock;
import upload.UpLoadFileInfo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class UploadTimerTask {
private UpLoadFileInfo upLoadFileInfo;
private boolean stop =
true;
private ExecutorService executorService = Executors.newSingleThreadExecutor();
public UploadTimerTask(UpLoadFileInfo upLoadFileInfo) {
this.upLoadFileInfo = upLoadFileInfo;
}
public void start() {
this.stop =
false;
executorService.execute(
new Runnable() {
@Override
public void run() {
while (!stop) {
upLoadFileInfo.hasUploadSizeBeforeOneSec = upLoadFileInfo.hasUploadSize;
SystemClock.sleep(
1000);
upLoadFileInfo.recLen++;
upLoadFileInfo.updateUploadSpeed();
}
}
}
);
}
public void stop() {
this.stop =
true;
}
}