Android使用OKHttp3实现下载(断点续传、显示进度)
来源:互联网 发布:重庆邮电大学就业知乎 编辑:程序博客网 时间:2024/06/11 21:14
- 转载自 http://blog.csdn.net/cfy137000/article/details/54838608 侵权删
- 在项目的build文件中配置java1.8
- defaultConfig {
- applicationId "com.lanou3g.downdemo"
- minSdkVersion 15
- targetSdkVersion 24
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- //为了开启Java8
- jackOptions{
- enabled true;
- //开启Java1.8 能够使用lambda表达式
- compileOptions{
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- //OKHttp
- compile 'com.squareup.okhttp3:okhttp:3.6.0'
- //RxJava和RxAndroid 用来做线程切换的
- compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
- compile 'io.reactivex.rxjava2:rxjava:2.0.1'
这是接下来的布局文件
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/activity_main"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:orientation="vertical"
- tools:context="com.lanou3g.downdemo.MainActivity">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <ProgressBar
- android:id="@+id/main_progress1"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- style="@style/Widget.AppCompat.ProgressBar.Horizontal" />
- <Button
- android:id="@+id/main_btn_down1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="下载1"/>
- <Button
- android:id="@+id/main_btn_cancel1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="取消1"/>
- </LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <ProgressBar
- android:id="@+id/main_progress2"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- style="@style/Widget.AppCompat.ProgressBar.Horizontal" />
- <Button
- android:id="@+id/main_btn_down2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="下载2"/>
- <Button
- android:id="@+id/main_btn_cancel2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="取消2"/>
- </LinearLayout>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <ProgressBar
- android:id="@+id/main_progress3"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="match_parent"
- style="@style/Widget.AppCompat.ProgressBar.Horizontal" />
- <Button
- android:id="@+id/main_btn_down3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="下载3"/>
- <Button
- android:id="@+id/main_btn_cancel3"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="取消3"/>
- </LinearLayout>
- </LinearLayout>
创建一个类继承application
- public class MyApp extends Application {
- public static Context sContext;//全局的Context对象
- @Override
- public void onCreate() {
- super.onCreate();
- sContext = this;
- }
- }
下载管理器
- public class DownloadManager {
- private static final AtomicReference<DownloadManager> INSTANCE = new AtomicReference<>();
- private HashMap<String, Call> downCalls;//用来存放各个下载的请求
- private OkHttpClient mClient;//OKHttpClient;
- //获得一个单例类
- public static DownloadManager getInstance() {
- for (; ; ) {
- DownloadManager current = INSTANCE.get();
- if (current != null) {
- return current;
- }
- current = new DownloadManager();
- if (INSTANCE.compareAndSet(null, current)) {
- return current;
- }
- }
- }
- private DownloadManager() {
- downCalls = new HashMap<>();
- mClient = new OkHttpClient.Builder().build();
- }
- /**
- * 开始下载
- *
- * @param url 下载请求的网址
- * @param downLoadObserver 用来回调的接口
- */
- public void download(String url, DownLoadObserver downLoadObserver) {
- Observable.just(url)
- .filter(s -> !downCalls.containsKey(s))//call的map已经有了,就证明正在下载,则这次不下载
- .flatMap(s -> Observable.just(createDownInfo(s)))
- .map(this::getRealFileName)//检测本地文件夹,生成新的文件名
- .flatMap(downloadInfo -> Observable.create(new DownloadSubscribe(downloadInfo)))//下载
- .observeOn(AndroidSchedulers.mainThread())//在主线程回调
- .subscribeOn(Schedulers.io())//在子线程执行
- .subscribe(downLoadObserver);//添加观察者
- }
- public void cancel(String url) {
- Call call = downCalls.get(url);
- if (call != null) {
- call.cancel();//取消
- }
- downCalls.remove(url);
- }
- /**
- * 创建DownInfo
- *
- * @param url 请求网址
- * @return DownInfo
- */
- private DownloadInfo createDownInfo(String url) {
- DownloadInfo downloadInfo = new DownloadInfo(url);
- long contentLength = getContentLength(url);//获得文件大小
- downloadInfo.setTotal(contentLength);
- String fileName = url.substring(url.lastIndexOf("/"));
- downloadInfo.setFileName(fileName);
- return downloadInfo;
- }
- private DownloadInfo getRealFileName(DownloadInfo downloadInfo) {
- String fileName = downloadInfo.getFileName();
- long downloadLength = 0, contentLength = downloadInfo.getTotal();
- File file = new File(MyApp.sContext.getFilesDir(), fileName);
- if (file.exists()) {
- //找到了文件,代表已经下载过,则获取其长度
- downloadLength = file.length();
- }
- //之前下载过,需要重新来一个文件
- int i = 1;
- while (downloadLength >= contentLength) {
- int dotIndex = fileName.lastIndexOf(".");
- String fileNameOther;
- if (dotIndex == -1) {
- fileNameOther = fileName + "(" + i + ")";
- } else {
- fileNameOther = fileName.substring(0, dotIndex)
- + "(" + i + ")" + fileName.substring(dotIndex);
- }
- File newFile = new File(MyApp.sContext.getFilesDir(), fileNameOther);
- file = newFile;
- downloadLength = newFile.length();
- i++;
- }
- //设置改变过的文件名/大小
- downloadInfo.setProgress(downloadLength);
- downloadInfo.setFileName(file.getName());
- return downloadInfo;
- }
- private class DownloadSubscribe implements ObservableOnSubscribe<DownloadInfo> {
- private DownloadInfo downloadInfo;
- public DownloadSubscribe(DownloadInfo downloadInfo) {
- this.downloadInfo = downloadInfo;
- }
- @Override
- public void subscribe(ObservableEmitter<DownloadInfo> e) throws Exception {
- String url = downloadInfo.getUrl();
- long downloadLength = downloadInfo.getProgress();//已经下载好的长度
- long contentLength = downloadInfo.getTotal();//文件的总长度
- //初始进度信息
- e.onNext(downloadInfo);
- Request request = new Request.Builder()
- //确定下载的范围,添加此头,则服务器就可以跳过已经下载好的部分
- .addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength)
- .url(url)
- .build();
- Call call = mClient.newCall(request);
- downCalls.put(url, call);//把这个添加到call里,方便取消
- Response response = call.execute();
- File file = new File(MyApp.sContext.getFilesDir(), downloadInfo.getFileName());
- InputStream is = null;
- FileOutputStream fileOutputStream = null;
- try {
- is = response.body().byteStream();
- fileOutputStream = new FileOutputStream(file, true);
- byte[] buffer = new byte[2048];//缓冲数组2kB
- int len;
- while ((len = is.read(buffer)) != -1) {
- fileOutputStream.write(buffer, 0, len);
- downloadLength += len;
- downloadInfo.setProgress(downloadLength);
- e.onNext(downloadInfo);
- }
- fileOutputStream.flush();
- downCalls.remove(url);
- } finally {
- //关闭IO流
- IOUtil.closeAll(is, fileOutputStream);
- }
- e.onComplete();//完成
- }
- }
- /**
- * 获取下载长度
- *
- * @param downloadUrl
- * @return
- */
- private long getContentLength(String downloadUrl) {
- Request request = new Request.Builder()
- .url(downloadUrl)
- .build();
- try {
- Response response = mClient.newCall(request).execute();
- if (response != null && response.isSuccessful()) {
- long contentLength = response.body().contentLength();
- response.close();
- return contentLength == 0 ? DownloadInfo.TOTAL_ERROR : contentLength;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return DownloadInfo.TOTAL_ERROR;
- }
- }
观察者
- public abstract class DownLoadObserver implements Observer<DownloadInfo> {
- protected Disposable d;//可以用于取消注册的监听者
- protected DownloadInfo downloadInfo;
- @Override
- public void onSubscribe(Disposable d) {
- this.d = d;
- }
- @Override
- public void onNext(DownloadInfo downloadInfo) {
- this.downloadInfo = downloadInfo;
- }
- @Override
- public void onError(Throwable e) {
- e.printStackTrace();
- }
- }
下载的注册信息
- public class DownloadInfo {
- public static final long TOTAL_ERROR = -1;//获取进度失败
- private String url;
- private long total;
- private long progress;
- private String fileName;
- public DownloadInfo(String url) {
- this.url = url;
- }
- public String getUrl() {
- return url;
- }
- public String getFileName() {
- return fileName;
- }
- public void setFileName(String fileName) {
- this.fileName = fileName;
- }
- public long getTotal() {
- return total;
- }
- public void setTotal(long total) {
- this.total = total;
- }
- public long getProgress() {
- return progress;
- }
- public void setProgress(long progress) {
- this.progress = progress;
- }
- }
判断是否为空 并且进行关闭
- public class IOUtil {
- public static void closeAll(Closeable... closeables){
- if(closeables == null){
- return;
- }
- for (Closeable closeable : closeables) {
- if(closeable!=null){
- try {
- closeable.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- private Button downloadBtn1, downloadBtn2, downloadBtn3;
- private Button cancelBtn1, cancelBtn2, cancelBtn3;
- private ProgressBar progress1, progress2, progress3;
- private String url1 = "http://192.168.31.169:8080/out/dream.flac";
- private String url2 = "http://192.168.31.169:8080/out/music.mp3";
- private String url3 = "http://192.168.31.169:8080/out/code.zip";
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- downloadBtn1 = bindView(R.id.main_btn_down1);
- downloadBtn2 = bindView(R.id.main_btn_down2);
- downloadBtn3 = bindView(R.id.main_btn_down3);
- cancelBtn1 = bindView(R.id.main_btn_cancel1);
- cancelBtn2 = bindView(R.id.main_btn_cancel2);
- cancelBtn3 = bindView(R.id.main_btn_cancel3);
- progress1 = bindView(R.id.main_progress1);
- progress2 = bindView(R.id.main_progress2);
- progress3 = bindView(R.id.main_progress3);
- downloadBtn1.setOnClickListener(this);
- downloadBtn2.setOnClickListener(this);
- downloadBtn3.setOnClickListener(this);
- cancelBtn1.setOnClickListener(this);
- cancelBtn2.setOnClickListener(this);
- cancelBtn3.setOnClickListener(this);
- }
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.main_btn_down1:
- DownloadManager.getInstance().download(url1, new DownLoadObserver() {
- @Override
- public void onNext(DownloadInfo value) {
- super.onNext(value);
- progress1.setMax((int) value.getTotal());
- progress1.setProgress((int) value.getProgress());
- }
- @Override
- public void onComplete() {
- if(downloadInfo != null){
- Toast.makeText(MainActivity.this,
- downloadInfo.getFileName() + "-DownloadComplete",
- Toast.LENGTH_SHORT).show();
- }
- }
- });
- break;
- case R.id.main_btn_down2:
- DownloadManager.getInstance().download(url2, new DownLoadObserver() {
- @Override
- public void onNext(DownloadInfo value) {
- super.onNext(value);
- progress2.setMax((int) value.getTotal());
- progress2.setProgress((int) value.getProgress());
- }
- @Override
- public void onComplete() {
- if(downloadInfo != null){
- Toast.makeText(MainActivity.this,
- downloadInfo.getFileName() + Uri.encode("下载完成"),
- Toast.LENGTH_SHORT).show();
- }
- }
- });
- break;
- case R.id.main_btn_down3:
- DownloadManager.getInstance().download(url3, new DownLoadObserver() {
- @Override
- public void onNext(DownloadInfo value) {
- super.onNext(value);
- progress3.setMax((int) value.getTotal());
- progress3.setProgress((int) value.getProgress());
- }
- @Override
- public void onComplete() {
- if(downloadInfo != null){
- Toast.makeText(MainActivity.this,
- downloadInfo.getFileName() + "下载完成",
- Toast.LENGTH_SHORT).show();
- }
- }
- });
- break;
- case R.id.main_btn_cancel1:
- DownloadManager.getInstance().cancel(url1);
- break;
- case R.id.main_btn_cancel2:
- DownloadManager.getInstance().cancel(url2);
- break;
- case R.id.main_btn_cancel3:
- DownloadManager.getInstance().cancel(url3);
- break;
- }
- }
- private <T extends View> T bindView(@IdRes int id){
- View viewById = findViewById(id);
- return (T) viewById;
- }
- }
阅读全文
0 1
- 使用OKHttp3实现下载(断点续传、显示进度)
- Android使用OKHttp3实现下载(断点续传、显示进度)
- Android使用OKHttp3实现下载(断点续传、显示进度)
- (二)使用libcurl实现获取目标文件大小, 下载进度显示, 断点续传等功能
- 使用libcurl实现获取目标文件大小, 下载进度显示, 断点续传等功能
- Android下载-实时进度-断点续传
- Android中使用Notification实现应用更新显示下载进度
- 使用OkHttp实现下载的进度监听和断点续传
- OkHttp3使用解析:实现下载进度的监听及其原理简析
- Android 文件下载,断点续传,进度更新
- Android 使用service实现多线程断点续传下载
- (二)操作libcurl实现获取目的文件大小, 下载进度显示, 断点续传
- Objective-C利用AFN实现图片下载,支持断点续传,显示下载进度
- Android实现Service下载文件,Notification显示下载进度
- iOS开发之网络编程--4、NSURLSessionDataTask实现文件下载(离线断点续传下载) <进度值显示优化>
- Notification实现下载进度显示!
- Notification实现下载进度显示!
- Notification实现下载进度显示!
- 综合练习之--1、复用布局页面显示XLV 和 侧滑 vp效果
- eclipse搭建JSF简单示例的教程(亲测)
- 值类型和引用类型误区
- 使用webstorm操作git
- display: inline-block换行问题
- Android使用OKHttp3实现下载(断点续传、显示进度)
- JavaScript的this机制与箭头函数(一)——this绑定的4种机制
- java代码实现对数据库的备份操作
- ImageLoaderConfiguration全局类配置+DisplayImageOptions图片适配----缓存到sd卡
- oracle optimizer_mode 参数
- as
- 验证手机号码的表达式
- 前端取值的方式(ModelMap)
- js模拟下拉选择<select>