视频预加载
This commit is contained in:
206
app/src/main/java/com/gh/download/cache/CacheManager.java
vendored
Normal file
206
app/src/main/java/com/gh/download/cache/CacheManager.java
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
package com.gh.download.cache;
|
||||
|
||||
import com.danikula.videocache.file.FileNameGenerator;
|
||||
import com.danikula.videocache.file.Md5FileNameGenerator;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.shuyu.gsyvideoplayer.utils.StorageUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
public class CacheManager {
|
||||
private static final AtomicReference<CacheManager> INSTANCE = new AtomicReference<>();
|
||||
private HashMap<String, Call> downCalls;
|
||||
private OkHttpClient mClient;
|
||||
private File cacheDirectory = StorageUtils.getIndividualCacheDirectory(HaloApp.getInstance().getApplication());
|
||||
private FileNameGenerator generator = new Md5FileNameGenerator();
|
||||
private final String TEMP_POSTFIX = ".download";
|
||||
private final int preLength = 5 * 1024 * 1024;//预加载大小
|
||||
|
||||
public static CacheManager getInstance() {
|
||||
for (; ; ) {
|
||||
CacheManager current = INSTANCE.get();
|
||||
if (current != null) {
|
||||
return current;
|
||||
}
|
||||
current = new CacheManager();
|
||||
if (INSTANCE.compareAndSet(null, current)) {
|
||||
return current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CacheManager() {
|
||||
downCalls = new HashMap<>();
|
||||
mClient = new OkHttpClient.Builder().build();
|
||||
}
|
||||
|
||||
public void download(String url, CacheObserver cacheObserver) {
|
||||
//当前url已下载完成则不再下载
|
||||
for (File file : getAllFile()) {
|
||||
if (file.getName().equals(generator.generate(url))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Observable.just(url)
|
||||
.filter(s -> !downCalls.containsKey(s))//call的map已经有了,就证明正在下载,则这次不下载
|
||||
.flatMap(s -> Observable.just(createDownInfo(s)))
|
||||
.map(this::getRealFileName)
|
||||
.flatMap(cacheInfo -> Observable.create(new DownloadSubscribe(cacheInfo)))
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(cacheObserver);
|
||||
|
||||
}
|
||||
|
||||
public void cancel(String url) {
|
||||
Call call = downCalls.get(url);
|
||||
if (call != null) {
|
||||
call.cancel();
|
||||
}
|
||||
downCalls.remove(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建DownInfo
|
||||
*
|
||||
* @param url 请求网址
|
||||
* @return DownInfo
|
||||
*/
|
||||
private CacheInfo createDownInfo(String url) {
|
||||
CacheInfo cacheInfo = new CacheInfo(url);
|
||||
long contentLength = getContentLength(url);//获得文件大小
|
||||
cacheInfo.setTotal(contentLength);
|
||||
String fileName = generator.generate(url) + TEMP_POSTFIX;
|
||||
cacheInfo.setFileName(fileName);
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
private CacheInfo getRealFileName(CacheInfo cacheInfo) {
|
||||
String fileName = cacheInfo.getFileName();
|
||||
long downloadLength = 0;
|
||||
if (!cacheDirectory.exists()) {
|
||||
cacheDirectory.mkdir();
|
||||
}
|
||||
File file = new File(cacheDirectory, fileName);
|
||||
if (file.exists()) {
|
||||
//找到了文件,代表已经下载过,则获取其长度
|
||||
downloadLength = file.length();
|
||||
}
|
||||
//设置改变过的文件名/大小
|
||||
cacheInfo.setProgress(downloadLength);
|
||||
cacheInfo.setFileName(file.getName());
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
|
||||
private class DownloadSubscribe implements ObservableOnSubscribe<CacheInfo> {
|
||||
private CacheInfo cacheInfo;
|
||||
|
||||
public DownloadSubscribe(CacheInfo cacheInfo) {
|
||||
this.cacheInfo = cacheInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribe(ObservableEmitter<CacheInfo> e) throws Exception {
|
||||
String url = cacheInfo.getUrl();
|
||||
long downloadLength = cacheInfo.getProgress();//已经下载好的长度
|
||||
long contentLength = cacheInfo.getTotal();//文件的总长度
|
||||
if (downloadLength >= preLength) {
|
||||
e.onComplete();
|
||||
return;
|
||||
}
|
||||
e.onNext(cacheInfo);
|
||||
Request request = new Request.Builder()
|
||||
.addHeader("RANGE", "bytes=" + downloadLength + "-" + (contentLength > preLength ? preLength : contentLength))
|
||||
.url(url)
|
||||
.build();
|
||||
Call call = mClient.newCall(request);
|
||||
downCalls.put(url, call);
|
||||
Response response = call.execute();
|
||||
File file = new File(cacheDirectory, cacheInfo.getFileName());
|
||||
InputStream is = null;
|
||||
FileOutputStream fileOutputStream = null;
|
||||
try {
|
||||
is = response.body().byteStream();
|
||||
fileOutputStream = new FileOutputStream(file, true);
|
||||
byte[] buffer = new byte[2048];
|
||||
int len;
|
||||
while ((len = is.read(buffer)) != -1) {
|
||||
fileOutputStream.write(buffer, 0, len);
|
||||
downloadLength += len;
|
||||
cacheInfo.setProgress(downloadLength);
|
||||
e.onNext(cacheInfo);
|
||||
}
|
||||
fileOutputStream.flush();
|
||||
downCalls.remove(url);
|
||||
} finally {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
if (fileOutputStream != null) {
|
||||
fileOutputStream.close();
|
||||
}
|
||||
}
|
||||
if (file.length() == contentLength){
|
||||
file.renameTo(new File(file.getPath().substring(0,file.getPath().lastIndexOf(TEMP_POSTFIX))));
|
||||
}
|
||||
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 ? CacheInfo.TOTAL_ERROR : contentLength;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return CacheInfo.TOTAL_ERROR;
|
||||
}
|
||||
|
||||
public void removeAllCall() {
|
||||
for (String key : downCalls.keySet()) {
|
||||
cancel(key);
|
||||
}
|
||||
}
|
||||
|
||||
private List<File> getAllFile() {
|
||||
if (cacheDirectory.exists()) {
|
||||
File[] files = cacheDirectory.listFiles();
|
||||
return Arrays.asList(files);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user