package com.zhan_dui.dictionary.utils;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.Notification;
import android.app.NotificationManager;
import android.os.AsyncTask;
import android.os.Environment;
import android.widget.ProgressBar;
import com.zhan_dui.dictionary.exceptions.SDCardUnmountedException;
/**
* 下载的工具类
*
* @author xuanqinanhai
*
*/
public class DownloadUtils {
private DownloadUtils() {
}
/**
* 这是DownloadUtils的工具函数,分别处理下载开始,下载出错,下载异常三种情况
*
* @author xuanqinanhai
*
*/
public interface DownloadUtilsInterface {
/**
* 在执行AsyncTask excute之前执行
*/
public boolean beforeDownload(String url);
/**
* 线程执行开始前的行为
*
* @param url
*/
public void beforeThread(String url);
/**
* 下载进度更新,共更新100次
*
* @param url
* 下载的文件地址
* @param fileDownladed
* 文件已经下载的大小
* @param fileSize
* 文件总大小
*/
public void update(String url, int fileDownladed, int fileSize);
/**
* 下载完成时执行(在线程里..可以开一个线程做一些解压、重命名、移动等操作)
*
* @param result
* 返回下载的结果
*/
public void afterThread(Boolean result, String url, String filePath);
/**
* 线程执行即将结束的行为
*
* @param result
* 下载文件是否成功
* @param url
* 文件URL
* @param filePath
* 文件保存的地址
*/
public void afterDownload(Boolean result, String url, String savePath);
/**
* 出错执行函数,errorMsg代表错误解释,可以直接输出
*
* @param errorMsg
*/
public void errorHand(String errorMsg, String url);
/**
* 在线程下载时候调用,注意,不要执行只能在UI线程上执行的行为,最好函数体越简单越好,这样就对下载速度的影响变小
*
* @param url
* 要终止下载的文件URL
* @return 返回是否终止下载
*/
public boolean isCanceled(String url);
/**
* 终止一个下载
*
* @param url
* 要终止下载的链接
*/
public void cancel(String url);
}
public static final String ERROR_CREATE_FILE = "创建文件错误";
public static final String ERROR_IO = "文件读写异常";
public static final String ERROR_WRONG_URL = "错误的URL格式";
public static final String ERROR_OPEN_URL = "打开URL连接出错";
public static final String ERROR_SD_CARD = "未检测到SD卡";
public static final String ERROR_CANCEL_DOWNLOAD = "您终止了下载";
private static class DownloadAsync extends
AsyncTask<Void, Integer, Boolean> {
String fileUrl, savePath;
DownloadUtils.DownloadUtilsInterface downloadBehavior;
String errorMsg;
int size = 0;// 文件大小
double downloaded = 0.0;
NotificationManager notificationManager;
Notification notification;
int progressbarId;
int notificationId;
boolean isUpdateNotification = false;
ProgressBar progressBar;
public DownloadAsync(String fileUrl, String savePath,
DownloadUtilsInterface downloadBehavior, ProgressBar progressBar) {
this.fileUrl = fileUrl;
this.savePath = savePath;
this.downloadBehavior = downloadBehavior;
this.progressBar = progressBar;
}
public DownloadAsync(String fileUrl, String savePath,
DownloadUtilsInterface downloadBehavior,
NotificationManager notificationManager,
Notification notification, int progressbarId, int notificationId) {
this.fileUrl = fileUrl;
this.savePath = savePath;
this.downloadBehavior = downloadBehavior;
this.notification = notification;
this.progressbarId = progressbarId;
this.isUpdateNotification = true;
this.notificationId = notificationId;
this.notificationManager = notificationManager;
}
protected void setFileSize(int size) {
this.size = size;
if (!isUpdateNotification) {
progressBar.setMax(size);
}
}
@Override
protected void onPreExecute() {
super.onPreExecute();
if (downloadBehavior.beforeDownload(this.fileUrl) == false) {
downloadBehavior.cancel(this.fileUrl);
}
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if (isUpdateNotification) {
notification.contentView.setProgressBar(progressbarId, 100,
values[0], false);
this.notificationManager.notify(notificationId, notification);
downloadBehavior.update(fileUrl, values[1], values[2]);
} else {
progressBar.setProgress(values[0]);
}
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (!result)
downloadBehavior.errorHand(errorMsg, this.fileUrl);
downloadBehavior.afterDownload(result, this.fileUrl, this.savePath);
if (isUpdateNotification) {
notificationManager.cancel(notificationId);
}
}
@Override
/**
* 后台线程下载
*/
protected Boolean doInBackground(Void... params) {
if (downloadBehavior.isCanceled(fileUrl)) {
errorMsg = ERROR_CANCEL_DOWNLOAD;
return false;
}
downloadBehavior.beforeThread(this.fileUrl);
File file = new File(savePath);
URL url = null;
InputStream fileInputStream = null;
HttpURLConnection httpURLConnection = null;
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
if (!Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
throw new SDCardUnmountedException();
}
if (file.exists() == false) {
if (file.getParentFile().exists() == false) {
file.getParentFile().mkdirs();
}
file.createNewFile();
}
url = new URL(fileUrl);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setInstanceFollowRedirects(true);
fileInputStream = httpURLConnection.getInputStream();
setFileSize(httpURLConnection.getContentLength());
fileOutputStream = new FileOutputStream(file);
bufferedOutputStream = new BufferedOutputStream(
fileOutputStream);
byte[] dataBuffer = new byte[1024];
int length = 0;
int downloadedPercentage;
int everyPieceSize = size / 100;
int oneTimeDownloadPieceSize = 0;
while ((length = fileInputStream.read(dataBuffer)) > 0) {
bufferedOutputStream.write(dataBuffer, 0, length);
oneTimeDownloadPieceSize += length;
if (oneTimeDownloadPieceSize > everyPieceSize) {
downloaded += oneTimeDownloadPieceSize;
downloadedPercentage = (int) ((downloaded / size) * 100);
publishProgress(downloadedPercentage, (int) downloaded,
size);
oneTimeDownloadPieceSize = 0;
}
if (downloadBehavior.isCanceled(fileUrl)) {
errorMsg = ERROR_CANCEL_DOWNLOAD;
break;
}
}
publishProgress(100, size, size);
} catch (MalformedURLException e) {
e.printStackTrace();
errorMsg = ERROR_WRONG_URL;
} catch (SDCardUnmountedException e) {
e.printStackTrace();
errorMsg = ERROR_SD_CARD;
} catch (IOException e) {
e.printStackTrace();
errorMsg = ERROR_IO;
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
errorMsg = ERROR_IO;
}
}
if (bufferedOutputStream != null) {
try {
bufferedOutputStream.flush();
bufferedOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
errorMsg = ERROR_IO;
}
}
}
downloadBehavior.afterThread(errorMsg == null, fileUrl, savePath);
return errorMsg == null;
}
}
/**
* 下载文件,更新进度条
*
* @param fileUrl
* 文件网络地址
* @param savePath
* 保存的地址
* @param progressBar
* 进度条对象,用来更新
* @param downlaodInterface
* 下载行为接口,分别会在下载前,下载时,下载后发送消息
*/
public static void download(String fileUrl, String savePath,
ProgressBar progressBar, DownloadUtilsInterface downlaodInterface) {
new DownloadAsync(fileUrl, savePath, downlaodInterface, progressBar)
.execute();
}
/**
* 下载文件并且通过notification更新
*
* @param fileUrl
* 文件地址
* @param savePath
* 保存地址
* @param downloadBehavior
* 下载行为接口,分别会在下载前,下载时,下载后发送消息
* @param notification
* 通知栏对象,用来更新通知栏下载进度
* @param progressbarId
* 通知栏中进度条ID
*
*/
public static void download(String fileUrl, String savePath,
DownloadUtilsInterface downloadBehavior,
NotificationManager notificationManager, Notification notification,
int progressbarId, int notificationId) {
new DownloadAsync(fileUrl, savePath, downloadBehavior,
notificationManager, notification, progressbarId,
notificationId).execute();
}
}