完整的OKhttp请求封装的网络框架
2017-08-04 19:12
591 查看
完整的OKhttp请求封装的网络框架
1.实现get,post等请求
2.支持上传,下载功能(支持断点续传)
3.支持Gson泛型解析json数据
4.使用mvc设计模式
5.封装glide图片库使用
6.支持自定义异常,异常的集中处理
7.添加缓存支持
8.支持log显示控制
9.支持文件上传下载
具体功能科参考项目中的网络框架使用demo和下载demo
下面针对断点续传的核心类,跟大家分享下,不对的地方还望指导;
实现思路:
使用OKHttp发送下载请求,通过下载管理器中的线程池控制多个线程,同时下载,默认支持5个任务。
在用户发送暂停下载命令时,结束当前下载线程,并保存当前下载任务的状态和下载已完成的大小。继续下载时,重新启动线程放入线程池中,开始下载前从数据库中获取对已的下载文件大小和状态,实现断点续传,继续下载,保存到文件中。
如以下代码中注释,描述实现过程:
源码下载地址
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); } } }
源码下载地址
相关文章推荐
- OKHttp网络请求封装好的框架
- 基于OkHttp3封装网络请求框架
- 安卓网络请求框架okHttp的使用与封装
- Android网络请求框架----Okhttp3完全解析(2),封装框架
- [置顶] 优雅设计封装基于Okhttp3的网络框架(完):原生HttpUrlConnction请求、多线程分发 及 数据转换
- 网络请求框架(二)----改善的okHttp封装库okhttputils的使用
- Android--menu和OkHttp框架(未封装),结合Executors(线程池)实现网络请求的案例
- okHttp网络请求框架get请求的封装
- Android 的OkHttp 网络请求框架的学习封装
- okhttp3的网络请求框架
- EasyHttp 基于OkHttp的网络请求框架
- android http——网络请求二次封装的框架设计
- 封装OkHttp的网络请求
- RxJava+Retrofit+OkHttp深入浅出-终极封装二(网络请求)
- 小程序-网络请求框架封装
- Okhttp作为现在最火的一个网络请求框架
- 网络请求工具类之OkHttp3封装(二)下(支持请求取消、异步请求的线程切换)
- 网络请求框架OkHttp基础用法
- OkHttp网络请求框架
- Okhttp使用简析——Android网络请求框架(一)