andorid http 多线程上传大文件

来源:互联网 发布:小米笔记本 游戏 知乎 编辑:程序博客网 时间:2024/06/06 12:40

最近学习研究了下用http进行大文件上传:

经过不断修复优化,功能实现如下:
1.上传大文件,(理论上GB以上都可以,上传速度视带宽而定);
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) {        //上传失败;1. 保存上传现场; 2. 提示失败原因        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(Tag, "headerInfo:" + sb.toString());        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);//设置0.5min 超时        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 {        //response:        final String responseMsg = getResponseMsg(conn);        Logger.d(Tag, "responseMsg:" + responseMsg);        //response:==================        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; // id in the database, if is from database    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;    }}
2 0
原创粉丝点击