开发下载文件的要求有两点:1.支持断点续传 2.后台有服务来下载文件。
1、复制xutils.jar到项目中 libs 点击下载
2、复制 核心类 到你的app文件下
DownloadInfo支持记录保存 。核心类下载
DownloadService有服务支持好处是所有activity关闭,下载不被中断。
DownloadManager作用。用来支持常见的下载操作。
配置服务。调用DownloadManager编写业务逻辑 下载 暂停 续传
DownloadInfo
public class DownloadInfo {
public DownloadInfo() {
}
private long id;
//一个应用只有一个appId 可以根据appId进行存储断点.方便下次查找断点
private String appId;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
@Transient
private HttpHandler handler;
private HttpHandler.State state;
private String downloadUrl;
private String fileName;
private String fileSavePath;
private long progress;
private long fileLength;
private boolean autoResume;
private boolean autoRename;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public HttpHandler getHandler() {
return handler;
}
public void setHandler(HttpHandler handler) {
this.handler = handler;
}
public HttpHandler.State getState() {
return state;
}
public void setState(HttpHandler.State state) {
this.state = state;
}
public String getDownloadUrl() {
return downloadUrl;
}
public void setDownloadUrl(String downloadUrl) {
this.downloadUrl = downloadUrl;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileSavePath() {
return fileSavePath;
}
public void setFileSavePath(String fileSavePath) {
this.fileSavePath = fileSavePath;
}
public long getProgress() {
return progress;
}
public void setProgress(long progress) {
this.progress = progress;
}
public long getFileLength() {
return fileLength;
}
public void setFileLength(long fileLength) {
this.fileLength = fileLength;
}
public boolean isAutoResume() {
return autoResume;
}
public void setAutoResume(boolean autoResume) {
this.autoResume = autoResume;
}
public boolean isAutoRename() {
return autoRename;
}
public void setAutoRename(boolean autoRename) {
this.autoRename = autoRename;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DownloadInfo)) return false;
DownloadInfo that = (DownloadInfo) o;
if (id != that.id) return false;
return true;
}
@Override
public int hashCode() {
return (int) (id ^ (id >>> 32));
}
}
DownloadService
public class DownloadService extends Service {
private static DownloadManager DOWNLOAD_MANAGER;
public static DownloadManager getDownloadManager(Context appContext) {
if (!DownloadService.isServiceRunning(appContext)) {
Intent downloadSvr = new Intent(appContext,DownloadService.class);
appContext.startService(downloadSvr);
}
if (DownloadService.DOWNLOAD_MANAGER == null) {
DownloadService.DOWNLOAD_MANAGER = new DownloadManager(appContext);
}
return DOWNLOAD_MANAGER;
}
public DownloadService() {
super();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public void onDestroy() {
if (DOWNLOAD_MANAGER != null) {
try {
DOWNLOAD_MANAGER.stopAllDownload();
DOWNLOAD_MANAGER.backupDownloadInfoList();
} catch (DbException e) {
LogUtils.e(e.getMessage(), e);
}
}
super.onDestroy();
}
public static boolean isServiceRunning(Context context) {
boolean isRunning = false;
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List serviceList = activityManager.getRunningServices(Integer.MAX_VALUE);
if (serviceList == null || serviceList.size() == 0) {
return false;
}
for (int i = 0; i < serviceList.size(); i++) {
if (serviceList.get(i).service.getClassName().equals(DownloadService.class.getName())) {
isRunning = true;
break;
}
}
return isRunning;
}
}
DownloadManager
public class DownloadManager {
private List downloadInfoList;
private int maxDownloadThread = 3;
private Context mContext;
private DbUtils db;
/* package */ DownloadManager(Context appContext) {
ColumnConverterFactory.registerColumnConverter(HttpHandler.State.class, new HttpHandlerStateConverter());
mContext = appContext;
db = DbUtils.create(mContext);// xUtils.db
try {
downloadInfoList = db.findAll(Selector.from(DownloadInfo.class));
} catch (DbException e) {
LogUtils.e(e.getMessage(), e);
}
if (downloadInfoList == null) {
downloadInfoList = new ArrayList();
}
}
public int getDownloadInfoListCount() {
return downloadInfoList.size();
}
public DownloadInfo getDownloadInfo(int index) {
return downloadInfoList.get(index);
}
/***
* 方法 按照应用appId查找断点记录
*
* @param appId
* @return
*/
public DownloadInfo getDownloadInfoByAppId(String appId) {
for (DownloadInfo item : downloadInfoList) {
if (TextUtils.equals(item.getAppId(), appId)) {
return item;// 返回指定appId的断点记录
}
}
return null;
}
public void addNewDownload(String appId, String url, String fileName, String target, boolean autoResume, boolean autoRename, final RequestCallBack callback) throws DbException {
final DownloadInfo downloadInfo = new DownloadInfo();
downloadInfo.setAppId(appId);
downloadInfo.setDownloadUrl(url);
downloadInfo.setAutoRename(autoRename);
downloadInfo.setAutoResume(autoResume);
downloadInfo.setFileName(fileName);
downloadInfo.setFileSavePath(target);
HttpUtils http = new HttpUtils();
http.configRequestThreadPoolSize(maxDownloadThread);
HttpHandler handler = http.download(url, target, autoResume, autoRename, new ManagerCallBack(downloadInfo, callback));
downloadInfo.setHandler(handler);
downloadInfo.setState(handler.getState());
downloadInfoList.add(downloadInfo);
db.saveBindingId(downloadInfo);
}
public void resumeDownload(int index, final RequestCallBack callback) throws DbException {
final DownloadInfo downloadInfo = downloadInfoList.get(index);
resumeDownload(downloadInfo, callback);
}
public void resumeDownload(DownloadInfo downloadInfo, final RequestCallBack callback) throws DbException {
HttpUtils http = new HttpUtils();
http.configRequestThreadPoolSize(maxDownloadThread);
HttpHandler handler = http.download(downloadInfo.getDownloadUrl(), downloadInfo.getFileSavePath(), downloadInfo.isAutoResume(), downloadInfo.isAutoRename(), new ManagerCallBack(downloadInfo, callback));
downloadInfo.setHandler(handler);
downloadInfo.setState(handler.getState());
db.saveOrUpdate(downloadInfo);
}
public void removeDownload(int index) throws DbException {
DownloadInfo downloadInfo = downloadInfoList.get(index);
removeDownload(downloadInfo);
}
public void removeDownload(DownloadInfo downloadInfo) throws DbException {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null && !handler.isCancelled()) {
handler.cancel();
}
// 从下载的断点记录集合中移除断点记录(内存)
downloadInfoList.remove(downloadInfo);
// 从数据库删除。
db.delete(downloadInfo);
// 下载一半的文件?100M 55M
String fileSavePath = downloadInfo.getFileSavePath();
// 如果存在下载一半的文件,由于下次找不到断点记录,没法续传,直接删除这个文件节省sd空间.
File file = new File(fileSavePath);
if (file.exists()) {
file.delete();
}
}
public void stopDownload(int index) throws DbException {
DownloadInfo downloadInfo = downloadInfoList.get(index);
stopDownload(downloadInfo);
}
public void stopDownload(DownloadInfo downloadInfo) throws DbException {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null && !handler.isCancelled()) {
handler.cancel();
} else {
downloadInfo.setState(HttpHandler.State.CANCELLED);
}
db.saveOrUpdate(downloadInfo);
}
public void stopAllDownload() throws DbException {
for (DownloadInfo downloadInfo : downloadInfoList) {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null && !handler.isCancelled()) {
handler.cancel();
} else {
downloadInfo.setState(HttpHandler.State.CANCELLED);
}
}
db.saveOrUpdateAll(downloadInfoList);
}
public void backupDownloadInfoList() throws DbException {
for (DownloadInfo downloadInfo : downloadInfoList) {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null) {
downloadInfo.setState(handler.getState());
}
}
db.saveOrUpdateAll(downloadInfoList);
}
public int getMaxDownloadThread() {
return maxDownloadThread;
}
public void setMaxDownloadThread(int maxDownloadThread) {
this.maxDownloadThread = maxDownloadThread;
}
public class ManagerCallBack extends RequestCallBack {
private DownloadInfo downloadInfo;
private RequestCallBack baseCallBack;
public RequestCallBack getBaseCallBack() {
return baseCallBack;
}
public void setBaseCallBack(RequestCallBack baseCallBack) {
this.baseCallBack = baseCallBack;
}
private ManagerCallBack(DownloadInfo downloadInfo, RequestCallBack baseCallBack) {
this.baseCallBack = baseCallBack;
this.downloadInfo = downloadInfo;
}
@Override
public Object getUserTag() {
if (baseCallBack == null)
return null;
return baseCallBack.getUserTag();
}
@Override
public void setUserTag(Object userTag) {
if (baseCallBack == null)
return;
baseCallBack.setUserTag(userTag);
}
@Override
public void onStart() {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null) {
downloadInfo.setState(handler.getState());
}
try {
db.saveOrUpdate(downloadInfo);
} catch (DbException e) {
LogUtils.e(e.getMessage(), e);
}
if (baseCallBack != null) {
baseCallBack.onStart();
}
}
@Override
public void onCancelled() {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null) {
downloadInfo.setState(handler.getState());
}
try {
db.saveOrUpdate(downloadInfo);
} catch (DbException e) {
LogUtils.e(e.getMessage(), e);
}
if (baseCallBack != null) {
baseCallBack.onCancelled();
}
}
@Override
public void onLoading(long total, long current, boolean isUploading) {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null) {
downloadInfo.setState(handler.getState());
}
downloadInfo.setFileLength(total);
downloadInfo.setProgress(current);
try {
db.saveOrUpdate(downloadInfo);
} catch (DbException e) {
LogUtils.e(e.getMessage(), e);
}
if (baseCallBack != null) {
baseCallBack.onLoading(total, current, isUploading);
}
}
@Override
public void onSuccess(ResponseInfo responseInfo) {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null) {
downloadInfo.setState(handler.getState());
}
try {
db.saveOrUpdate(downloadInfo);
} catch (DbException e) {
LogUtils.e(e.getMessage(), e);
}
if (baseCallBack != null) {
baseCallBack.onSuccess(responseInfo);
}
}
@Override
public void onFailure(HttpException error, String msg) {
HttpHandler handler = downloadInfo.getHandler();
if (handler != null) {
downloadInfo.setState(handler.getState());
}
try {
db.saveOrUpdate(downloadInfo);
} catch (DbException e) {
LogUtils.e(e.getMessage(), e);
}
if (baseCallBack != null) {
baseCallBack.onFailure(error, msg);
}
}
}
private class HttpHandlerStateConverter implements ColumnConverter {
@Override
public HttpHandler.State getFieldValue(Cursor cursor, int index) {
return HttpHandler.State.valueOf(cursor.getInt(index));
}
@Override
public HttpHandler.State getFieldValue(String fieldStringValue) {
if (fieldStringValue == null)
return null;
return HttpHandler.State.valueOf(fieldStringValue);
}
@Override
public Object fieldValue2ColumnValue(HttpHandler.State fieldValue) {
return fieldValue.value();
}
@Override
public ColumnDbType getColumnDbType() {
return ColumnDbType.INTEGER;
}
}
}
//获取DownloadManager对象
DownloadManager mg = DownloadService.getDownloadManager(MyApp.getContext());
//按钮BtnDownload的点击事件
BtnDownload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
//查询指定应用下载记录(断点 progress)
DownloadInfo downloadInfo = mg.getDownloadInfoByAppId(data.id + "");
//判断是否有下载记录,有就是续传 没有就是开始下载
if (downloadInfo == null) {
//参数1 appId应用编号
String appId = data.id + "";
//参数2 下载地址
String url = ApiUrls.DOWNLOAD + data.downloadUrl;
//参数3 文件名
String fileName = data.name;
//参数4 保存的绝对路径
String target = Environment.getExternalStorageDirectory().getAbsolutePath() + "/market/" + data.packageName + ".apk";
//参数5 是否支持断点
boolean autoResume = true;
//参数6 是否重命名
boolean autoRename = false;
//参数回调对象,处理界面更新业务逻辑
mg.addNewDownload(appId, url, fileName, target, autoResume, autoRename, callback);
} else {
//继续传输
//载按钮点击事件
//loading当前出入下载状态
if (downloadInfo.getState() == HttpHandler.State.LOADING) {
mg.stopDownload(downloadInfo);
part5BtnDownload.setText("继续");
} else {
mg.resumeDownload(downloadInfo, callback);
}
}
}catch(Exception e){e.printStackTrace();}
}
});
由于整个下载过程没有界面更新,用户不知道下载进度,所以编写进度更新的业务逻辑。编写在CallBack空方法里面
RequestCallBack callback= new RequestCallBack(){
//下载过程中进度变化
@Override
public void onLoading(long total, long current, boolean isUploading) {
super.onLoading(total, current, isUploading);
//设置进度条的进度文本
//设置进度条最大值、设置当前进度
if(total==0){total=1;}
int percent = (int) (current*100f/total+0.5f);
BtnDownload.setText(percent+"%");
PbarProgress.setMax(100);//PbarProgress进度条
PbarProgress.setProgress(percent);
}
@Override
public void onSuccess(ResponseInfo responseInfo) {
part5BtnDownload.setText("安装");
part5PbarProgress.setMax(100);
part5PbarProgress.setProgress(100);
//调用隐式意图安装
ApkUtil.install((Activity) context,responseInfo.result.getAbsolutePath());
}
@Override
public void onFailure(HttpException e, String s) {
part5BtnDownload.setText("继续");
}
};
/**
*APK安装工具类
*/
public class ApkUtil {
public static void install(Activity activity,String target){
//Intent :开启服务或者打开页面
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
String type = "application/vnd.android.package-archive";
// http://www.itheima.com f /mnt/sdcard
Uri data = Uri.parse("file:///" + target);
intent.setDataAndType(data, type);
activity.startActivity(intent);
}
}
进入页面需要进行回显(把断点记录下来,设置给界面)
private void resumeDownLoadInfo(String appId) {
//5.1获取断点记录
DownloadInfo downloadInfo = mg.getDownloadInfoByAppId(appId);
if (downloadInfo == null) {
part5BtnDownload.setText("下载");
part5PbarProgress.setMax(100);
part5PbarProgress.setProgress(0);
} else {
//5.2计算百分比
long total = downloadInfo.getFileLength();
if (total == 0) {
total = 1;
}
int percent = (int) (downloadInfo.getProgress() * 100f / total + 0.5f);
part5PbarProgress.setMax(100);
part5PbarProgress.setProgress(percent);
if (downloadInfo.getState() == HttpHandler.State.LOADING) {
part5BtnDownload.setText(percent + "%");
} else {
part5BtnDownload.setText("继续");
}
}
}