android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }
}
依赖
implementation 'io.reactivex.rxjava2:rxjava:2.1.3' implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.squareup.okhttp3:okhttp:3.2.0'
1.先建立 DownloadInfo类
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; } }
2.建立 DownloadManager类
import android.os.Environment; import android.util.Log; import com.example.lenovo.jiuyue.App; 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 陈丰尧 on 2017/2/2. */ 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 */ public 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(Environment.getExternalStorageDirectory().getAbsolutePath() + "/九悦/", fileName); Log.e("DownloadManager", "file:" + file); 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(Environment.getExternalStorageDirectory().getAbsolutePath() + "/九悦/", fileNameOther); Log.e("DownloadManager", "newFile:" + newFile); 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(Environment.getExternalStorageDirectory().getAbsolutePath() + "/九悦/", 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 { is.close(); fileOutputStream.close(); //关闭IO流 } 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; } }
3.DownLoadObserver
import io.reactivex.Observer; import io.reactivex.disposables.Disposable; /** * Created by 陈丰尧 on 2017/2/2. */ 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(); } }
MainActivity
boolean biao=true; @OnClick(R.id.bt_download) public void onViewClicked() { if(biao){ biao=false; xiazais.setImageResource(R.drawable.tasks_not_downloaded); DownloadManager.getInstance().download(url, new DownLoadObserver() { @Override public void onNext(DownloadInfo value) { super.onNext(value); double houss = (value.getTotal() * 1.00 / 1024 / 1000); double qainss = (value.getProgress() * 1.00 / 1024 / 1000); BigDecimal bg = new BigDecimal(houss); double jin1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); BigDecimal bg1 = new BigDecimal(qainss); double jin2 = bg1.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); hou.setText(jin1 + "M"); qian.setText(jin2 + "M"); } @Override public void onComplete() { if (downloadInfo != null) { Toast.makeText(ShiPinActivity.this, downloadInfo.getFileName() + "-DownloadComplete", Toast.LENGTH_SHORT).show(); videoplayer.setVisibility(View.GONE); videoView.setVisibility(View.VISIBLE); String str = Environment.getExternalStorageDirectory() + "/九悦/"+downloadInfo.getFileName(); Uri uri = Uri.parse("file://" + str); videoView.setMediaController(new MediaController(ShiPinActivity.this)); videoView.setVideoURI(uri); videoView.start(); videoView.requestFocus(); } } }); }else { xiazais.setImageResource(R.drawable.tasks_paused); biao = true; DownloadManager.getInstance().cancel(url); }}
扫描二维码关注公众号,回复:
2483687 查看本文章