完整的OKhttp请求封装的网络框架

来源:互联网 发布:网络推广平均工资 编辑:程序博客网 时间:2024/05/22 13:21

完整的OKhttp请求封装的网络框架

1.实现get,post等请求
2.支持上传,下载功能(支持断点续传)
3.支持Gson泛型解析json数据
4.使用mvc设计模式
5.封装glide图片库使用
6.支持自定义异常,异常的集中处理
7.添加缓存支持
8.支持log显示控制
9.支持文件上传下载

具体功能科参考项目中的网络框架使用demo和下载demo

下面针对断点续传的核心类,跟大家分享下,不对的地方还望指导;

实现思路:
使用OKHttp发送下载请求,通过下载管理器中的线程池控制多个线程,同时下载,默认支持5个任务。
在用户发送暂停下载命令时,结束当前下载线程,并保存当前下载任务的状态和下载已完成的大小。继续下载时,重新启动线程放入线程池中,开始下载前从数据库中获取对已的下载文件大小和状态,实现断点续传,继续下载,保存到文件中。

如以下代码中注释,描述实现过程:

public class DownLoadTask implements Runnable {        private static String FILE_MODE = "rwd";        private OkHttpClient mClient;        private Call call;        // 便于对跳转到文件的指定位置,进行读写操作        private RandomAccessFile mDownLoadFile;        // 这里使用greendao保存数据        private DownloadEntity dbEntity;        private DownloadDao mDownloadDao;        private DownloadTaskListener mListener;        // 包装传递下载要使用的信息        private Builder mBuilder;        private String id;// task id        private long totalSize;// filesize        private long completedSize; //  Download section has been completed        private String url;// file url        private String saveDirPath;// file save path        private String fileName; // File name when saving        private int downloadStatus;        // 下载百分百        private int percent;        // 下载失败code        private int errorCode;        private DownLoadTask(Builder builder) {            this.mBuilder = builder;            this.id = mBuilder.id;            this.url = mBuilder.url;            this.saveDirPath = mBuilder.saveDirPath;            this.fileName = mBuilder.fileName;            this.downloadStatus = mBuilder.downloadStatus;            this.mListener = mBuilder.listener;        }        @Override        public void run() {            try {                // 数据库中加载数据,不为空说明下载过(可能未下载完成)                dbEntity = mDownloadDao.load(id);                if (dbEntity != null) {                    completedSize = dbEntity.getCompletedSize();                    totalSize = dbEntity.getTotalSize();                }                // 获得文件保存路径                String filepath = getDownLoadFilePath().getAbsolutePath();                // 获得下载保存文件                mDownLoadFile = new RandomAccessFile(filepath, FILE_MODE);                // 获得本地下载的文件大小                long fileLength = mDownLoadFile.length();                // 本地文件的大小和数据库中保存的文件大小相同,说明下载完成,直接返回                if (fileLength > 0 && totalSize == fileLength) {                    downloadStatus = DownloadStatus.DOWNLOAD_STATUS_COMPLETED;                    completedSize = fileLength;                    totalSize = fileLength;                    percent = 100;                    WLog.d("totalSize=" + totalSize + " ,completedSize=" + completedSize + " ,downloadStatus="                        + downloadStatus);                    // 执行回调,通知界面层                    onCallBack();                    return;                }                // ============没有下过或下载为完成,则开始下载==================                Request request = new Request.Builder().url(url)//                    .header("RANGE", "bytes=" + completedSize + "-") // Http value set breakpoints RANGE                    .build();                // 文件跳转到指定位置开始写入                mDownLoadFile.seek(completedSize);                // 创建一个下载请求                call = mClient.newCall(request);                call.enqueue(new Callback() {                    @Override                    public void onFailure(Call call, IOException e) {                        // 发送错误事件                         error();                    }                    @Override                    public void onResponse(Call call, Response response) throws IOException {                        ResponseBody body = response.body();                        if (body != null) {                            // 更新回调下载状态,初始化为正在下载                            downloadStatus = DownloadStatus.DOWNLOAD_STATUS_DOWNLOADING;                            // 回调更新界面层                            onCallBack();                            // 开始下载                            readAndSave2File(body.byteStream(), body.contentLength());                        }                    }                });            } catch (FileNotFoundException e) {                // file not found                WLog.e(e.getMessage());                error();            } catch (IOException e) {                // io exception                WLog.e(e.getMessage());                error();            }        }        // 读取下载流,并保存到文件中        private void readAndSave2File(InputStream inputStream, final long contentLength) throws IOException {            byte[] buf = new byte[2048];            int length = 0;            try {                long sum = completedSize;                float times = 0;                // contentLength 在暂停后再次启动会从断点后开始计算,会小于文件原始的大小                // 所以只能在第一次加载的时候保存获取文件大小,否则计算百分百会不对                if (totalSize <= 0) {                    totalSize = contentLength;                }                while ((length = inputStream.read(buf)) != -1) {                    // 如果不是正在下载状态,则停止任务,结束下载                    if (downloadStatus != DownloadStatus.DOWNLOAD_STATUS_DOWNLOADING) {                        return;                    }                    sum += length;                    mDownLoadFile.write(buf, 0, length);                    completedSize = sum;                    // 计算百分比                    float prgress = (float) (completedSize * 100 / totalSize);                    // WLog.d("completedSize=" + completedSize + " ,prgress=" + prgress);                    // 防止频繁的更新界面,控制更新进度,回调100次                    if (prgress - times >= 1) {                        times = prgress;                        // 更新状态                        downloadStatus = DownloadStatus.DOWNLOAD_STATUS_DOWNLOADING;                        // 更新百分比                        percent = (int) prgress;                        onCallBack();                    }                }            } catch (Exception e) {                WLog.e(e.toString());            } finally {                // 任务结束,最终都会执行的地方                WLog.d("completedSize=" + completedSize);                // 回收资源                close(inputStream);                close(mDownLoadFile);                // 判断是否下载完成,更新下载状态                isDownloadFinish();                // 最终都会执行,数据库更新                insertOrUpdateDB();                // 回调一次                onCallBack();            }        }        // 判断文件下载是否完成(下载的大小是否与文件大小相等)        private boolean isDownloadFinish() {            boolean finish = false;            if (totalSize > 0 && completedSize > 0 && totalSize == completedSize) {                downloadStatus = DownloadStatus.DOWNLOAD_STATUS_COMPLETED;                finish = true;            }            return finish;        }        /**         * 更新数据库操作         */        private void insertOrUpdateDB() {            if (dbEntity == null) {                dbEntity = new DownloadEntity(id, totalSize, completedSize, url, saveDirPath, fileName, downloadStatus);            }            else {                dbEntity.setCompletedSize(completedSize);                dbEntity.setDownloadStatus(downloadStatus);            }            mDownloadDao.insertOrReplace(dbEntity);            WLog.d("totalSize=" + dbEntity.getTotalSize() + " ,completedSize=" + dbEntity.getCompletedSize()                + " ,downloadStatus=" + dbEntity.getDownloadStatus());        }        /**         * error 事件处理         */        private void error() {            downloadStatus = DownloadStatus.DOWNLOAD_STATUS_ERROR;            errorCode = DownloadStatus.DOWNLOAD_ERROR_IO_ERROR;            onCallBack();        }        /**         * 取消下载         */        public void cancel() {            downloadStatus = DownloadStatus.DOWNLOAD_STATUS_CANCEL;            doCancelClear();            cancelRequest();            onCallBack();        }        /**         * 暂停下载         */        public void pause() {            downloadStatus = DownloadStatus.DOWNLOAD_STATUS_PAUSE;            onCallBack();        }        /**         * 取消下载请求         */        private void cancelRequest() {            if (call != null) {                if (!call.isCanceled()) {                    call.cancel();                }            }        }        /**         * 删除本地文件和数据库数据         */        private void doCancelClear() {            if (dbEntity != null) {                mDownloadDao.delete(dbEntity);                File temp = getDownLoadFilePath();                if (temp.exists()) {                    temp.delete();                }            }        }        /**         * 分发回调事件到ui层         */        private void onCallBack() {            // 发送当前下载状态            mHandler.sendEmptyMessage(downloadStatus);            // 同步manager中的task信息            DownloadManager.getInstance().updateDownloadTask(this);        }        Handler mHandler = new Handler(Looper.getMainLooper()) {            @Override            public void handleMessage(Message msg) {                int code = msg.what;                switch (code) {                    // 下载失败                    case DownloadStatus.DOWNLOAD_STATUS_ERROR:                        mListener.onError(DownLoadTask.this, errorCode);                        break;                    // 正在下载                    case DownloadStatus.DOWNLOAD_STATUS_DOWNLOADING:                        mListener.onDownloading(DownLoadTask.this, completedSize, totalSize, percent);                        break;                    // 取消                    case DownloadStatus.DOWNLOAD_STATUS_CANCEL:                        mListener.onCancel(DownLoadTask.this);                        break;                    // 完成                    case DownloadStatus.DOWNLOAD_STATUS_COMPLETED:                        mListener.onDownloadSuccess(DownLoadTask.this, getDownLoadFilePath());                        break;                    // 停止                    case DownloadStatus.DOWNLOAD_STATUS_PAUSE:                        mListener.onPause(DownLoadTask.this, completedSize, totalSize, percent);                        break;                }            }        };        // 获得文件保存路径        private File getDownLoadFilePath() {            File file = FileUtil.getDownLoadDir();            String parentDir = file.getAbsolutePath();            // 获得文件名            String filename = !TextUtils.isEmpty(fileName) ? fileName : getFileNameFromUrl(url);            File downFile = new File(parentDir, filename);            return downFile;        }        @Override        public boolean equals(Object obj) {            if(obj instanceof DownLoadTask){                DownLoadTask task = (DownLoadTask) obj;                return task.getId().equals(this.getId());            }            return super.equals(obj);        }        //=============================================================        public void setDownloadDao(DownloadDao mDownloadDao) {            this.mDownloadDao = mDownloadDao;        }        public Builder getBuilder() {            return mBuilder;        }        public void setBuilder(Builder builder) {            this.mBuilder = builder;        }        public String getId() {            return id;        }        public String getUrl() {            return url;        }        public String getSaveDirPath() {            return saveDirPath;        }        public String getFileName() {            return fileName;        }        public void setClient(OkHttpClient mClient) {            this.mClient = mClient;        }        public void setTotalSize(long totalSize) {            this.totalSize = totalSize;        }        public void setCompletedSize(long completedSize) {            this.completedSize = completedSize;        }        public void setDownloadStatus(int downloadStatus) {            this.downloadStatus = downloadStatus;        }        public int getDownloadStatus() {            return downloadStatus;        }        public static class Builder {            private String id;// task id            private String url;// file url            private String saveDirPath;// file save path            private String fileName; // File name when saving            private int downloadStatus = DownloadStatus.DOWNLOAD_STATUS_INIT;            private DownloadTaskListener listener;            /**             * 作为下载task开始、删除、停止的key值(not null)             *             * @param id             * @return             */            public Builder setId(String id) {                this.id = id;                return this;            }            /**             * 下载url(not null)             *             * @param url             * @return             */            public Builder setUrl(String url) {                this.url = url;                return this;            }            /**             * 设置保存地址             *             * @param saveDirPath             * @return             */            public Builder setSaveDirPath(String saveDirPath) {                this.saveDirPath = saveDirPath;                return this;            }            /**             * 设置下载状态             *             * @param downloadStatus             * @return             */            public Builder setDownloadStatus(int downloadStatus) {                this.downloadStatus = downloadStatus;                return this;            }            /**             * 设置文件名             *             * @param fileName             * @return             */            public Builder setFileName(String fileName) {                this.fileName = fileName;                return this;            }            /**             * 设置下载回调             *             * @param listener             * @return             */            public Builder setListener(DownloadTaskListener listener) {                this.listener = listener;                return this;            }            public DownLoadTask build() {                return new DownLoadTask(this);            }        }    }

这里写图片描述

这里写图片描述

源码下载地址

原创粉丝点击