Android 中 文件下载
首先要先创建一个文件缓存的Util类:MultiTaskDownloadManager 要实现 MultiTask 接口类
当时的需求是接口返回给客户端一个链接,然后根据链接地址去缓存文件,
package cn.wostore.gloud.api.download;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import com.tencent.mm.opensdk.utils.Log;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import cn.wostore.gloud.MainApplication;
import cn.wostore.gloud.downloads.db.DaoMaster;
import cn.wostore.gloud.downloads.db.DaoSession;
import cn.wostore.gloud.downloads.db.DownloadInfoDao;
import cn.wostore.gloud.utils.Constant;
import cn.wostore.gloud.utils.MathUtil;
import cn.wostore.gloud.utils.SPDownloadUtil;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class MultiTaskDownloadManager implements MultiTask {
private static final AtomicReference<MultiTaskDownloadManager> INSTANCE = new AtomicReference<>();
private Map<String, ProgressDownloader> downCalls; //用来存放各个下载的请求
private static String FILE_PATH = Constant.APP_ROOT_PATH + Constant.DOWNLOADS_DIR;
private Map<String, Long> fileContentLengthCache;
private Map<String, File> apkFileCaches;
private DownloadInfoDao downloadInfoDao;
public static MultiTaskDownloadManager getInstance() {
for (; ; ) {
MultiTaskDownloadManager current = INSTANCE.get();
if (current != null) {
return current;
}
current = new MultiTaskDownloadManager();
if (INSTANCE.compareAndSet(null, current)) {
return current;
}
}
}
private MultiTaskDownloadManager() {
downCalls = new HashMap<>();
fileContentLengthCache = new HashMap<>();
apkFileCaches = new HashMap<>();
initDownloadDB();
}
/**
* 开启缓存
* */
@Override
public void start(DownloadInfo downloadInfo) {
if (getDownloadPercent(downloadInfo.getDownloadUrl())[1] == 100) {
if (getDownloadUrl(downloadInfo.getDownloadUrl())) {
downCalls.remove(downloadInfo.getDownloadUrl());
}
return;
}
if (!getDownloadUrl(downloadInfo.getDownloadUrl())) {
createDownloadUrl(downloadInfo.getDownloadUrl(), downloadInfo);
}
}
@Override
public void start(String url) {
if (getDownloadPercent(url)[1] == 100) {
if (getDownloadUrl(url)) {
downCalls.remove(url);
}
return;
}
if (!getDownloadUrl(url)) {
createDownloadUrl(url, null);
}
}
/**
* 暂停缓存
* */
@Override
public void stop(String url) {
if (getDownloadUrl(url)) {
downCalls.get(url).pause();
downCalls.remove(url);
}
}
@Override
public void delete(String url) {
stop(url);
File file = getFilePath(url);
if (file != null && file.exists()) {
file.delete();
}
clearCache(url);
}
/**
* 删除缓存的任务
* */
@Override
public void delete(DownloadInfo info) {
deleteDownloadTask(info);
delete(info.getDownloadUrl());
}
/**
* 删除所有缓存的任务(可用于全选删除)
* /
@Override
public void deleteAll() {
File allFiles = new File(FILE_PATH);
deleteDir(allFiles);
SPDownloadUtil.getInstance().clear();
clearDownloadTasks();
fileContentLengthCache.clear();
apkFileCaches.clear();
Iterator<Map.Entry<String, ProgressDownloader>> iterator = downCalls.entrySet().iterator();
while (iterator.hasNext()) {
iterator.next().getValue().pause();
iterator.remove();
}
}
/*
* 清除缓存
*/
public void clearCache(String url) {
SPDownloadUtil.getInstance().removeContentLength(url);
if (fileContentLengthCache.containsKey(url)) {
fileContentLengthCache.remove(url);
}
if (apkFileCaches.containsKey(url)) {
apkFileCaches.remove(url);
}
}
/**
* 创建下载地址
*/
private void createDownloadUrl(String url, DownloadInfo info) {
File apkFile = getFilePath(url);
Observable.create(e -> {
ProgressDownloader downloader = new ProgressDownloader(url, apkFile, new ProgressResponseBody.ProgressListener() {
@Override
public void onPreExecute(long contentLength) {
if ((!apkFile.exists() || apkFile.length() == 0) && contentLength > 200) {
SPDownloadUtil.getInstance().saveContentLength(url, contentLength);
fileContentLengthCache.put(url, contentLength);
}
}
@Override
public void update(long totalBytes, long contentLength, boolean done) {
e.onNext(info == null ? url : info);
if (done && getDownloadUrl(url)) {
// 下载完成
downCalls.remove(url);
}
}
@Override
public void onError(Throwable e) {
if (getDownloadUrl(url)) {
downCalls.remove(url);
}
clearCache(url);
}
});
downCalls.put(url, downloader);
downloader.download(apkFile.exists() ? apkFile.length() : 0L);
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DownloadObserver());
}
/**
* 获取要下载的地址
/
public boolean getDownloadUrl(String url) {
return downCalls.containsKey(url);
}
/*
* 获取文件路径
/
public File getFilePath(String url) {
String[] datas = url.split("/");
final String fileName = datas[datas.length - 1];
File pathFile = new File(FILE_PATH);
if (!pathFile.exists()) {
pathFile.mkdirs();
}
File file = new File(FILE_PATH + fileName);
return file;
}
/*
* 删除缓存到本地的文件目录
*/
private void deleteDir(File file) {
if (!file.exists()) {
return;
}
if (file.isFile()) {
file.delete();
} else {
File[] files = file.listFiles();
if (files == null) {
file.delete();
} else {
for (int i = 0; i < files.length; i++) {
deleteDir(files[i]);
}
file.delete();
}
}
}
/**
* 获取 当前已下载大小、文件总大小,以及进度(百分比)
*
* @param url 下载链接
* @return 返回结果为一个数据arr(arr[0]已经下载的文件大小 、 arr[1]文件总大小 、 arr[2]文件下载进度 百分比)
*/
public long[] getDownloadPercent(String url) {
File file;
if (apkFileCaches.containsKey(url) && apkFileCaches.get(url) != null && apkFileCaches.get(url).exists()) {
file = apkFileCaches.get(url);
} else {
file = getFilePath(url);
apkFileCaches.put(url, file);
}
long contentLength;
if (fileContentLengthCache.containsKey(url)) {
contentLength = fileContentLengthCache.get(url);
} else {
contentLength = SPDownloadUtil.getInstance().getContentLength(url, 0);
fileContentLengthCache.put(url, contentLength);
}
if (!file.exists() || contentLength == 0) {
clearCache(url);
return new long[]{0, 0, 0};
}
return new long[]{file.length(), contentLength, (file.length() * 100 / contentLength)};
}
private class DownloadObserver implements Observer<Object> {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Object obj) {
String url;
DownloadInfo info = null;
if (obj instanceof DownloadInfo) {
info = (DownloadInfo) obj;
url = info.getDownloadUrl();
} else {
url = (String) obj;
}
long[] s = getDownloadPercent(url);
if (downloadListener != null) {
info.setProgress(s[0]);
info.setContentLenth(s[1]);
info.setPercent(s[2]);
downloadListener.onProgress(s[0], s[1], s[2], info);
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
@Override
public void onComplete() {
}
}
private void initDownloadDB() {
//初始化 第二个参数随便取名,为数据库的名字
DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(MainApplication.getInstance(), "数据库的名称", null);
DaoMaster daoMaster = new DaoMaster(devOpenHelper.getWritableDatabase());
DaoSession daoSession = daoMaster.newSession();
downloadInfoDao = daoSession.getDownloadInfoDao();
}
/**
* 添加下载任务
*
* @param downloadInfo
*/
@Override
public void insertTask(DownloadInfo downloadInfo) {
downloadInfo.setId(null);//传null可以自增,不用设值
downloadInfoDao.insert(downloadInfo);
}
/**
* 获取单个下载任务
*
* @param downloadInfo
* @return
*/
@Override
public DownloadInfo getDownloadInfo(DownloadInfo downloadInfo) {
List<DownloadInfo> infos = downloadInfoDao.queryBuilder().where(DownloadInfoDao.Properties.DownloadUrl.eq(downloadInfo.getDownloadUrl()))
.build().list();
return infos != null && infos.size() > 0 ? infos.get(0) : null;
}
/**
* 获取下载任务列表
*
* @return
*/
@Override
public List<DownloadInfo> getDownloadTasks() {
return downloadInfoDao.loadAll();
}
/**
* 清空全部下载任务(sqlite)
*/
private void clearDownloadTasks() {
downloadInfoDao.deleteAll();
}
/**
* 删除单个下载任务(sqlite)
*
* @param info
*/
private void deleteDownloadTask(DownloadInfo info) {
DownloadInfo downloadInfo = getDownloadInfo(info);
if (downloadInfo != null) {
downloadInfoDao.delete(downloadInfo);
}
}
/**
* 单位转换
*
* @param sizeInt
* @return
*/
public String formatSize(long sizeInt) {
String[] value = new String[2];
if (sizeInt == 0) {
return "0MB";
}
double b = 1024;
double kb = b * b;
double mb = kb * b;
double gb = mb * b;
java.text.DecimalFormat df_one = new java.text.DecimalFormat("#0.0");
java.text.DecimalFormat df_two = new java.text.DecimalFormat("#0.00");
if (sizeInt < b) {
return (int) sizeInt + "B";
} else if (sizeInt < kb) {
value[0] = String.format("%s", df_two.format(MathUtil.div(sizeInt, b, 2)));
value[1] = "KB";
} else if (sizeInt < mb) {
// 保留两位小数
value[0] = String.format("%s", df_two.format(MathUtil.div(sizeInt, kb, 2)));
value[1] = "MB";
} else if (sizeInt < gb) {
value[0] = String.format("%s", df_two.format(MathUtil.div(sizeInt, kb, 2)));
value[1] = "MB";
} else {
value[0] = String.format("%s", df_two.format(MathUtil.div(sizeInt, mb, 2)));
value[1] = "GB";
}
return value[0] + value[1];
}
public boolean isAppInstalled(Context context, String url) {
String[] urls = url.split("/");
String pkgName = null;
PackageInfo packageInfo;
try {
if (urls[urls.length - 1].indexOf("_") > -1) {
pkgName = urls[urls.length - 1].split("_")[1].substring(0, urls[urls.length - 1].split("_")[1].length() - 4);
} else {
pkgName = urls[urls.length - 1].substring(0, urls[urls.length - 1].length() - 4);
}
packageInfo = context.getPackageManager().getPackageInfo(pkgName, 0);
} catch (PackageManager.NameNotFoundException e) {
packageInfo = null;
e.printStackTrace();
}
//没有安装APK
return packageInfo != null;
}
private DownloadListener downloadListener;
public void setDownloadListener(DownloadListener downloadListener) {
this.downloadListener = downloadListener;
}
public interface DownloadListener {
void onProgress(long current, long total, long percent, DownloadInfo info);
}
}
这样就可以实现自己要实现的效果了