Android--okhttp断点下载+进度
import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.Toast; 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://dl175.80s.im:920/1803/西游记女儿国/西游记女儿国.mp4"; private String url2 = "http://dl174.80s.im:920/1803/湮灭/湮灭.mp4"; private String url3 = "http://dl173.80s.im:920/1803/南极之恋/南极之恋.mp4"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); downloadBtn1 = findViewById(R.id.main_btn_down1); downloadBtn2 = findViewById(R.id.main_btn_down2); downloadBtn3 = findViewById(R.id.main_btn_down3); cancelBtn1 = findViewById(R.id.main_btn_cancel1); cancelBtn2 = findViewById(R.id.main_btn_cancel2); cancelBtn3 = findViewById(R.id.main_btn_cancel3); progress1 = findViewById(R.id.main_progress1); progress2 = findViewById(R.id.main_progress2); progress3 = findViewById(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; } } }
import android.os.Environment; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.concurrent.atomic.AtomicReference; import io.reactivex.Observable; import io.reactivex.ObservableEmitter; import io.reactivex.ObservableOnSubscribe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; /** * Created by xiaobai on 2018/3/30/030. */ public class DownloadManager { private static final AtomicReference<DownloadManager> INSTANCE = new AtomicReference<>(); private HashMap<String, Call> downCalls;//用来存放各个下载的请求 private OkHttpClient mClient;//OKHttpClient; private String FILEPATH = Environment.getExternalStorageDirectory().getAbsolutePath()+"/"; //获得一个单例类 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(FILEPATH, 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(MyApplication.getContext().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(MyApplication.getContext().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; } }
APK和DEMO下载: https://download.csdn.net/download/chaoyu168/10317361 分享一个简单的下载工具类;
import android.os.Environment; import android.support.annotation.NonNull; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; /** *下载工具 */ public class DownloadUtil { private static DownloadUtil downloadUtil; private final OkHttpClient okHttpClient; public static DownloadUtil get() { if (downloadUtil == null) { downloadUtil = new DownloadUtil(); } return downloadUtil; } private DownloadUtil() { okHttpClient = new OkHttpClient(); } /** * @param url 下载连接 * @param saveDir 储存下载文件的SDCard目录 * @param listener 下载监听 */ public void download(final String url, final String saveDir, final OnDownloadListener listener) { Request request = new Request.Builder().url(url).build(); okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 下载失败 listener.onDownloadFailed(); } @Override public void onResponse(Call call, Response response) throws IOException { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; // 储存下载文件的目录 String savePath = isExistDir(saveDir); try { is = response.body().byteStream(); long total = response.body().contentLength(); File file = new File(savePath, getNameFromUrl(url)); fos = new FileOutputStream(file); long sum = 0; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); sum += len; int progress = (int) (sum * 1.0f / total * 100); // 下载中 listener.onDownloading(progress); } fos.flush(); // 下载完成 listener.onDownloadSuccess(); } catch (Exception e) { listener.onDownloadFailed(); } finally { try { if (is != null) is.close(); } catch (IOException e) { } try { if (fos != null) fos.close(); } catch (IOException e) { } } } }); } /** * @param saveDir * @return * @throws IOException * 判断下载目录是否存在 */ private String isExistDir(String saveDir) throws IOException { // 下载位置 File downloadFile = new File(Environment.getExternalStorageDirectory(), saveDir); if (!downloadFile.mkdirs()) { downloadFile.createNewFile(); } String savePath = downloadFile.getAbsolutePath(); return savePath; } /** * @param url * @return * 从下载连接中解析出文件名 */ @NonNull private String getNameFromUrl(String url) { return url.substring(url.lastIndexOf("/") + 1); } public interface OnDownloadListener { /** * 下载成功 */ void onDownloadSuccess(); /** * @param progress * 下载进度 */ void onDownloading(int progress); /** * 下载失败 */ void onDownloadFailed(); } }
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Kotlin的包的新特性
一、如果你用过JAVA就会对包非常熟悉了 一句话:就是一个命名空间定位,包就是你可根据包路径去找到指定的文件 在写Java代码的时候,在导入包或者引用类的时候,下图就是在用类的时候,需要导入。根据包路径就能找到所用的类 二、用大学来举下例子 三、实际运用下(在生产环境,正式开发时候,请勿使用中午包名) package net.大学.地球.亚洲.中国.北京 //如果在Java中这么取别名编译器是不允许的 //import java.util.List as HelloList; //java中是错的 import net.大学.地球.亚洲.日本.东京.University as JapenUniversity /** * @author:wangdong * @description: */ fun main(args: Array<String>) { //这是直接给出说 val PekingUniversity: University = University("北京大学") //因为北京和东京下的两个University类名相同,所以在特指使用的时候,需要明确指出所引的...
- 下一篇
Java for循环删除ArrayList重复元素陷阱,Iterator迭代器遍历删除重复元素
Java for循环删除ArrayList重复元素陷阱,Iterator迭代器遍历删除重复元素 这是一个一不留神就犯下错误的Java列表ArrayList重复删除元素陷阱,并且问题比较隐蔽。问题描述,假设一个ArrayList存储若干个字符串String元素,这些元素中存在若干重复的、一模一样的元素,编程实现把这些重复元素全部删除。 常见的代码写法是for循环定点删除: ArrayList<String> mLists = new ArrayList<>(); mLists.add("zhang"); mLists.add("phil"); mLists.add("csdn"); mLists.add("csdn"); mLists.add("csdn"); for (int i = 0; i < mLists.size(); i++) { String s = mLists.get(i); if(s.equals("csdn")) mLists.remove(i); } for(int i=0;i<mLists.size();i++){ Syste...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS8编译安装MySQL8.0.19