安卓最简单的文件下载, 基于OkHttp,包含下载进度、断点续传
2017-10-29 14:26
851 查看
安卓最简单的文件下载, 基于OkHttp,包含下载进度、断点续传
前言
安卓中的文件下载功能相信大多数人并不陌生了,自己在网上也看到过很多写的非常棒的文章,尤其是基于OkHttp、Retrofit等近年来比较火的网络框架,其实真正的文件下载功能有了这些优秀网络框架的支持,已经简单了许多,难点在于那些之外的业务场景,比如定义下载进度、断点续传等功能,下面我就基于OkHttp实现这两个功能。首先我们做一些初始化的工作
在build.gradle文件中添加OkHttp的依赖 :compile 'com.squareup.okhttp3:okhttp:3.9.0'
添加所需要的权限(友情提示:安卓6.0以上的记得动态权限):
网络权限:
<uses-permission android:name="android.permission.INTERNET" />
存储权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
测试的下载地址:
http://softfile.3g.qq.com:8080/msoft/179/24659/43549/qq_hd_mini_1.4.apk
文件存放路径(就放在根路径下):
Environment.getExternalStorageDirectory() + "/myDownload.apk"
实现普通的下载功能
这里因为OkHttp的封装,只是一些Api的调用,就不过多解释了:Request request = new Request.Builder() .url(URL) .build(); OkHttpClient okHttpClient = new OkHttpClient.Builder() .build(); Call call = okHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { //失败的时候回调,打印异常信息 Log.e(TAG, "onFailure: -------- " + e.getMessage()); } @Override public void onResponse(Call call, Response response) { InputStream is = null; FileOutputStream fos = null; try { //得到一个流文件 is = response.body().byteStream(); fos = new FileOutputStream(FILE_PATH); byte[] buf = new byte[2048]; int len = 0; //将文件写入本地(再次友情提示:记得权限问题) while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); } fos.flush(); } catch (IOException e) { Log.e(TAG, "Exception: ----------- :" + e.getMessage()); } finally { try { if (fos != null) { fos.close(); } if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } } } });
监听下载文件的进度
增加进度监听,变化其实并不大,我们只需要知道两个值,1、该文件的总大小;2、该文件实时的写入大小。经过摸索,我发现可以通过response.body().contentLength();来获取文件总大小,实时写入大小是我们自己控制的,所以那就好办了,上代码:直接跳到前边普通下载功能的onResponse方法中,其他地方没有变化。
FileOutputStream fos = null; InputStream is = null; try { ResponseBody body = response.body(); long totleBytes = body.contentLength();//得到文件的总大小 is = body.byteStream();//得到一个流文件 fos = new FileOutputStream(FILE_PATH); byte[] buffer = new byte[2048]; //初始化当前已下载的字节 long currentBytes = 0L; int len = 0; //将文件写入本地(再次友情提示:记得权限问题) while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); //每次写入的大小累加 currentBytes += len; //转换得到当前下载的进度% int progress = (int) ((currentBytes * 100) / totleBytes); Log.e(TAG, "onResponse: --------- 下载进度:" + progress + "%"); } fos.flush(); } catch (IOException e) { Log.e(TAG, "Exception: ---------------:" + e.getMessage()); } finally { try { if (fos != null) { fos.close(); } if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } }
断点续传
说到断点续传,不得不提到Java中一个非常强大的文件读写类:RandomAccessFile,翻译叫“随机读写文件”类,其中有两个重要的方法:方法名 作用
getFilePointer() 返回文件记录指针的当前位置;
seek(long pos) 将文件记录指针移动到某个位置,并可以从当前位置进行追加写入。
此外,要想OkHttp支持断点下载,必须添加一个请求头addHeader(“RANGE”, “bytes=断点的位置-“),这样我们每次请求下来的就只是文件剩余的字节,再通过RandomAccessFile的seek()方法插入到指定的位置,将剩余的字节写入即可:
try { File file = new File(FILE_PATH); if (!file.exists()) { file.createNewFile(); } //定义一个随机读写类,"rwd"模式:数据更新同步写入到底层存储设备 final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rwd"); //这里拿到文件的大小,如果是新建的文件,则文件大小为0,否则就是已经下载的文件字节数 final long fileBytes = file.length(); Request request = new Request.Builder() .url(URL) //拉取自己需要的那部分字节 .addHeader("RANGE", "bytes=" + fileBytes + "-") .build(); OkHttpClient okHttpClient = new OkHttpClient.Builder() .build(); Call call = okHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { //失败的时候回调,打印异常信息 Log.e(TAG, "onFailure: -------- " + e.getMessage()); } @Override public void onResponse(Call call, Response response) { InputStream is = null; try { ResponseBody body = response.body(); is = body.byteStream(); //取出缓存的文件总大小 long contentLength = SharedPreferencedUtils.getLong(mContext, "contentLength", 0L); if (contentLength <= 0L) { //这里的Length为每次请求下来的大小,并不是文件本身的总大小,所以为了计算下载进度,这里将文件总大小缓存 contentLength = body.contentLength(); //存一下文件的总大小 SharedPreferencedUtils.setLong(mContext, "contentLength", contentLength); } //将文件记录指针移动到上一次写入文件的位置 randomAccessFile.seek(fileBytes); byte[] buffer = new byte[2048]; //当前已经缓存的字节 = 文件的字节大小 long currentBytes = fileBytes; int len = 0; while (-1 != (len = is.read(buffer))) { randomAccessFile.write(buffer, 0, len); //每次写入的大小累加 currentBytes += len; //转换得到当前下载的进度% int progress = (int) ((currentBytes * 100) / contentLength); Log.e(TAG, "onResponse: --------- 下载进度:" + progress + "%"); } } catch (IOException e) { Log.e(TAG, "Exception: -------------:" + e.getMessage()); } finally { try { if (is != null) { is.close(); } if (randomAccessFile != null) { randomAccessFile.close(); } } catch (IOException e) { e.printStackTrace(); } } } }); } catch (IOException e) { Log.e(TAG, "Exception: -------------:" + e.getMessage()); }
ok!功能实现,有没有觉得很简单? 有什么不妥的地方,或者更好的方案,欢迎大家指出。
相关文章推荐
- RxJava + Retrofit+okhttp 封装,包含对相同格式请求数据、相同格式返回数据处理,显示 Material Design 加载 dialog,文件上传下载进度展示、全局异常捕捉。
- ios开发视频播放后台下载功能实现 :1,ios播放视频 ,包含基于AVPlayer播放器,2,实现下载,iOS后台下载(多任务同时下载,单任务下载,下载进度,下载百分比,文件大小,下载状态)(真机调试功能正常)
- Android okhttp+rxjava实现多文件下载和断点续传
- 简单实现的自定义圆环进度条,可使用于文件的上传下载图片加载等地方.
- 使用OkHttp实现下载的进度监听和断点续传
- 基于Java的一个简单的文件上传下载功能
- 文件下载_断点续传_进度查看
- Android okhttp 下载文件到指定文件夹带进度更新加7.0适配
- [置顶] Android使用okhttp封装多文件批量下载 (带进度条,取消下载)
- android使用OkHttp实现下载的进度监听和断点续传
- Android OkHttp文件上传与下载的进度监听扩展
- 多线程下载文件和断点续传的简单实现
- Android 文件下载引擎,稳定、高效、简单易用:FileDownloader(结合okhttp)
- Android OkHttp文件上传与下载的进度监听扩展
- 基于Retrofit+Okio+RxBus实现文件下载(带下载进度)
- 基于Retrofit+Okio+RxBus实现文件下载(带下载进度)
- OKHTTP_三行代码实现文件下载(dialog显示进度)
- 基于Retrofit+Rxjava实现带进度显示的下载文件
- OkHttp学习(2)-->>异步下载图片、文件(拦截器重写Response方法实现下载进度获取)
- 使用OKHttp上传、下载文件记录进度