package com.leelen.test;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler;
import android.os.StatFs;
import android.text.TextUtils;
/**
* 注:无限循环下载,不因报错而停止,除非手动停止。
* 需要网络权限和读写权限
* <uses-permission android:name="android.permission.INTERNET" />
* <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
*/
public class DownloaderManager {
private static final String TAG = "DownloaderManager";
private static final String KEY_SP = "key_downloader";
private Context mContext = null;
private class DownloadFileInfo {
String mDownloadUrl = "";
String mSavePath = "";
int mFileLength = 0;
int mDownloadSize = 0;
}
private DownloadFileInfo mDFI = null;
private SharedPreferences mPreferences = null;
private boolean isPause = false;
private boolean isStop = false;
private boolean isWifiOnly = true;
private Handler mHandler = new Handler();
/**
* 因无限循环,所以以下大部分回调都可能多次调用。
*/
public interface OnDownloadListener {
void onEnter();
void onProgress(int fileLength, int downloadSize, float percent);
void onPause();
void onIOError();
void onNetworkError();
void onSpaceError();
void onExit(boolean isFinish);
}
private OnDownloadListener mListener = null;
/**
* 创建后即开始下载,不主动调用结束,就一直在下载
* 网络、空间出错时,会通过回调上报
* 注意:不因为出错而结束,如果想结束,要主动调用stop
*
* @param context
* @param listener
* 回调侦听,显示错误及进度等
* @param downloadUrl
* 下载地址
* @param savePath
* 文件存储全路径,包括路径和文件名(请保证路径存在,本程序不负责创建路径,只负责创建下载的文件)
*/
public DownloaderManager(Context context, OnDownloadListener listener,
String downloadUrl, String savePath) {
mContext = context;
mListener = listener;
MyLogI("downladUrl = " + downloadUrl);
MyLogI("savePath = " + savePath);
if (TextUtils.isEmpty(downloadUrl)) {
MyLogE("empty url");
onListenerExit(false);
return;
}
if (TextUtils.isEmpty(savePath)) {
MyLogE("empty savePath");
onListenerExit(false);
return;
}
getInfo(downloadUrl, savePath);
new Thread(new Runnable() {
@Override
public void run() {
try { // 延迟开启下载
Thread.sleep(100);
} catch (InterruptedException e) {
}
doDownload();
}
}).start();
}
// 继续
public void resume() {
isPause = false;
}
// 暂停
public void pause() {
isPause = true;
}
// 判断是否暂停
public boolean isPause() {
return isPause;
}
// 停止
public void stop() {
isStop = true;
}
// 判断是否停止
public boolean isStop() {
return isStop;
}
// 设置数据网络可下载
public void setWifiOnly(boolean wifiOnly) {
isWifiOnly = wifiOnly;
}
// 是否只有wifi下可下载
public boolean isWifiOnly() {
return isWifiOnly;
}
// ------ 获取下载信息 0 ------
public String getDownloadUrl() {
if (mDFI != null) {
return mDFI.mDownloadUrl;
}
return "";
}
public String getSavePath() {
if (mDFI != null) {
return mDFI.mSavePath;
}
return "";
}
public int getFileLength() {
if (mDFI != null) {
return mDFI.mFileLength;
}
return 0;
}
public int getDownloadSize() {
if (mDFI != null) {
return mDFI.mDownloadSize;
}
return 0;
}
// ------ 获取下载信息 1 ------
// 执行下载
private void doDownload() {
MyLogW("doDownload() enter");
onListenerEnter();
int count = 0;
int COUNT_MAX = 20;
InputStream is = null;
RandomAccessFile raf = null;
boolean isError = false;
while (true) {
try {
isError = false;
if (isStop) { // 结束下载
MyLogI("doDownload() isStop = " + isStop);
break;
}
// 判断是否暂停以及网络是否可用
if (!isPause && isNetworkAvailable()) {
// 打开连接
URLConnection urlConn = new URL(mDFI.mDownloadUrl).openConnection();
if (mDFI.mFileLength <= 0) { // 获取文件大小
mDFI.mFileLength = urlConn.getContentLength();
}
MyLogI("doDownload() mDFI.mFileLength = " + mDFI.mFileLength);
MyLogI("doDownload() mDFI.mDownloadSize = " + mDFI.mDownloadSize);
if (mDFI.mFileLength > 0 && isSpaceEnough()) {
File file = new File(mDFI.mSavePath);
if (file.exists()) { // 本地文件存在
MyLogI("doDownload() file.length() = " + file.length());
if (mDFI.mFileLength == file.length()) { // 已完成下载
mDFI.mDownloadSize = mDFI.mFileLength;
isStop = true;
MyLogW("doDownload() download complete!");
break;
} else { // 下载未完成
if (mDFI.mDownloadSize != file.length()) {
MyLogW("doDownload() file size error : delete");
file.delete(); // 文件大小不对,说明已被改变,直接删除重新下载
mDFI.mDownloadSize = 0;
}
}
}
is = urlConn.getInputStream();
raf = new RandomAccessFile(mDFI.mSavePath, "rw");
if (mDFI.mDownloadSize > 0) {
long byteCount = is.skip(mDFI.mDownloadSize);
MyLogE("doDownload() skip byteCount = " + byteCount + ", mDFI.mDownloadSize = " + mDFI.mDownloadSize);
if (byteCount == mDFI.mDownloadSize) {
raf.seek(mDFI.mDownloadSize);
} else {
isError = true;
}
}
if (!isError) {
int len = 0;
byte[] bytes = new byte[10240];
while (true) {
if (isStop) { // 结束下载
MyLogI("doDownload() isStop = " + isStop);
break;
}
isError = false;
// 判断网络是否可用
if (!isPause && !isNetworkAvailable()) {
isError = true;
}
// 判断空间是否足够
if (!isPause && !isSpaceEnough()) {
isError = true;
}
// 判断是否暂停或出错
if (!isPause && !isError) {
len = is.read(bytes);
if (len != (-1)) { // 未完成
raf.write(bytes, 0, len);
mDFI.mDownloadSize += len; // 改变下载大小
count ++;
if (count >= COUNT_MAX) {
count = 0;
float percent = ((int) ((mDFI.mDownloadSize / (float) mDFI.mFileLength) * 1000)) / (float) 10;
MyLogI("doDownload() download mDFI.mFileLength = " + mDFI.mFileLength
+ ", mDFI.mDownloadSize = " + mDFI.mDownloadSize
+ ", percent = " + percent);
onListenerProgress(mDFI.mFileLength, mDFI.mDownloadSize, percent);
}
} else {
if (mDFI.mDownloadSize == mDFI.mFileLength) { // 完成
isStop = true;
MyLogI("doDownload() download mDFI.mFileLength = " + mDFI.mFileLength
+ ", mDFI.mDownloadSize = " + mDFI.mDownloadSize);
MyLogW("doDownload() download complete now!");
onListenerProgress(mDFI.mFileLength, mDFI.mDownloadSize, 100);
} else { // 下载失败
MyLogE("doDownload() download mDFI.mFileLength = " + mDFI.mFileLength
+ ", mDFI.mDownloadSize = " + mDFI.mDownloadSize);
MyLogE("doDownload() error mDownloadSize != mFileLength");
mDFI.mDownloadSize = 0; // 设置重新下载
}
break;
}
} else if (isPause) {
MyLogW("doDownload() is pause");
onListenerPause();
}
if (!isStop) {
try { // 进入休眠,不能老占用资源
if (isPause || isError) {
Thread.sleep(3000); // 暂停或出错时,休眠时间长一些
} else { // 未出错时,休眠时间短些
Thread.sleep(10);
}
} catch (InterruptedException e) {
MyLogW("doDownload() InterruptedException");
}
}
}
}
}
} else if (isPause) {
MyLogW("doDownload() is pause");
onListenerPause();
}
} catch (IOException e) {
e.printStackTrace();
MyLogW("doDownload() IOException");
onListenerIOError();
} finally {
if (raf != null) {
try {
raf.close();
raf = null;
} catch (IOException e) {
e.printStackTrace();
MyLogW("doDownload() IOException");
onListenerIOError();
}
}
if (is != null) {
try {
is.close();
is = null;
} catch (IOException e) {
e.printStackTrace();
MyLogW("doDownload() IOException");
onListenerIOError();
}
}
}
if (!isStop) {
try { // 进入休眠,不能老占用资源
Thread.sleep(3000);
} catch (InterruptedException e) {
MyLogW("doDownload() InterruptedException");
}
}
}
saveInfo();
boolean isFinish = false;
if (mDFI != null) {
MyLogW("mDFI.mFileLength = " + mDFI.mFileLength +
", mDFI.mDownloadSize = " + mDFI.mDownloadSize);
if (mDFI.mFileLength > 0 && mDFI.mFileLength == mDFI.mDownloadSize) {
isFinish = true;
}
}
MyLogW("doDownload() exit isFinish = " + isFinish);
onListenerExit(isFinish);
}
// MD5
private String getMd5(String s) {
if (TextUtils.isEmpty(s)) {
return s;
}
try {
// Create MD5 Hash
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
for (int i = 0, v = 0; i < messageDigest.length; i++) {
v = 0xFF & messageDigest[i];
if (v < 16) {
hexString.append("0");
}
hexString.append(Integer.toHexString(v));
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
}
return s;
}
// 读取上次下载信息
private void getInfo(String downloadUrl, String savePath) {
// 初始化下载信息
if (mDFI == null) {
mDFI = new DownloadFileInfo();
}
mDFI.mDownloadUrl = downloadUrl;
mDFI.mSavePath = savePath;
mDFI.mFileLength = 0;
mDFI.mDownloadSize = 0;
// 获取保存信息
if (mPreferences == null) {
mPreferences = mContext.getSharedPreferences(KEY_SP, Context.MODE_PRIVATE);
}
JSONObject json = new JSONObject();
try {
json.put("url", downloadUrl);
json.put("path", savePath);
String jsonStr = mPreferences.getString(getMd5(json.toString()), "");
if (!TextUtils.isEmpty(jsonStr)) {
json = new JSONObject(jsonStr);
mDFI.mDownloadUrl = json.getString("url");
mDFI.mSavePath = json.getString("path");
mDFI.mFileLength = json.getInt("length");
mDFI.mDownloadSize = json.getInt("size");
}
} catch (JSONException e) {
}
MyLogI("mDFI.mDownloadUrl = " + mDFI.mDownloadUrl);
MyLogI("mDFI.mSavePath = " + mDFI.mSavePath);
MyLogI("mDFI.mFileLength = " + mDFI.mFileLength);
MyLogI("mDFI.mDownloadSize = " + mDFI.mDownloadSize);
}
private void saveInfo() {
// 初始化下载信息
if (mDFI == null) {
return;
}
// 保存信息
if (mPreferences == null) {
mPreferences = mContext.getSharedPreferences(KEY_SP, Context.MODE_PRIVATE);
}
JSONObject json = new JSONObject();
try {
json.put("url", mDFI.mDownloadUrl);
json.put("path", mDFI.mSavePath);
String jsonStr = json.toString();
json.put("length", mDFI.mFileLength);
json.put("size", mDFI.mDownloadSize);
Editor editor = mPreferences.edit();
if (mDFI.mFileLength == mDFI.mDownloadSize) {
editor.putString(getMd5(jsonStr), "");
} else {
editor.putString(getMd5(jsonStr), json.toString());
}
editor.commit();
} catch (JSONException e) {
}
}
// 获取网络制式
private static final String WIFI = "WIFI";
private static final String MOBILE = "MOBILE";
private String getNetworkType() {
String strNetworkType = "";
try { // 获取网络信息
NetworkInfo networkInfo = ((ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE))
.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
strNetworkType = WIFI; // WIFI
} else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
strNetworkType = MOBILE; // 数据网络
}
}
} catch (Throwable e) {
}
return strNetworkType;
}
// 网络是否可用
private boolean isNetworkAvailable() {
boolean isAvailable = false;
String networkType = getNetworkType();
if (TextUtils.isEmpty(networkType)) { // 无网络
} else if (TextUtils.equals(networkType, WIFI)) { // WIFI
isAvailable = true;
} else if (TextUtils.equals(networkType, MOBILE)) { // 数据网络
if (!isWifiOnly) {
isAvailable = true;
} else { // 人为设置数据网络是否可用于下载
String path = Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + "wifi_ex";
if (new File(path).exists()) {
isAvailable = true;
}
}
}
if (!isAvailable) {
MyLogW("isNetworkAvailable() isAvailable = " + isAvailable);
onListenerNetworkError();
}
return isAvailable;
}
// 获取空间大小
@SuppressWarnings("deprecation")
private long getVacantSpaceSize(String path) {
StatFs fileStats = new StatFs(path);
fileStats.restat(path);
long size = (long) fileStats.getAvailableBlocks() * (long) fileStats.getBlockSize();
return size;
}
// 空间富余量,即比要下载的文件大小多出多少空间,默认12MB
private long SPACE_MORE = 12 * 1024 * 1024;
// 设置空间富余量
public void setSpaceMore(long more) {
SPACE_MORE = more;
}
// 空间是否足够
private boolean isSpaceEnough() {
boolean isEnough = true;
// 获取sd卡剩余空间大小
long vacantSpace = getVacantSpaceSize(Environment.getExternalStorageDirectory()
.getAbsolutePath());
// 文件大小
int fileLength = 0;
// 完成下载大小
int downloadSize = 0;
// 初始化文件和下载大小
if (mDFI != null) {
fileLength = mDFI.mFileLength;
downloadSize = mDFI.mDownloadSize;
}
// 剩余空间比需要下载的文件大小多出富余大小以上,被认为是空间足够
if (fileLength + SPACE_MORE - downloadSize >= vacantSpace) {
isEnough = false;
}
// 人为设置空间是否足够
String path = Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + "low_space";
if (new File(path).exists()) {
isEnough = false;
}
if (!isEnough) {
MyLogW("isSpaceEnough() false");
onListenerSpaceError();
}
return isEnough;
}
// ------ 侦听回调处理 0 ------
private void onListenerEnter() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onEnter();
}
}
});
}
}
private void onListenerProgress(final int fileLength, final int downloadSize,
final float percent) {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onProgress(fileLength, downloadSize, percent);
}
}
});
}
}
private void onListenerPause() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onPause();
}
}
});
}
}
private void onListenerIOError() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onIOError();
}
}
});
}
}
private void onListenerNetworkError() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onNetworkError();
}
}
});
}
}
private void onListenerSpaceError() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onSpaceError();
}
}
});
}
}
private void onListenerExit(final boolean isFinish) {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onExit(isFinish);
}
}
});
}
}
// ------ 侦听回调处理 1 ------
// ------ 打印相关 0 ------
private void MyLogE(String info) {
android.util.Log.e(TAG, info);
}
private void MyLogW(String info) {
android.util.Log.w(TAG, info);
}
private boolean isInfoLog = false;
public void setIsInfoLog(boolean isLog) {
isInfoLog = isLog;
}
private void MyLogI(String info) {
if (isInfoLog) {
android.util.Log.i(TAG, info);
}
}
// ------ 打印相关 1 ------
}
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler;
import android.os.StatFs;
import android.text.TextUtils;
/**
* 注:无限循环下载,不因报错而停止,除非手动停止。
* 需要网络权限和读写权限
* <uses-permission android:name="android.permission.INTERNET" />
* <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
*/
public class DownloaderManager {
private static final String TAG = "DownloaderManager";
private static final String KEY_SP = "key_downloader";
private Context mContext = null;
private class DownloadFileInfo {
String mDownloadUrl = "";
String mSavePath = "";
int mFileLength = 0;
int mDownloadSize = 0;
}
private DownloadFileInfo mDFI = null;
private SharedPreferences mPreferences = null;
private boolean isPause = false;
private boolean isStop = false;
private boolean isWifiOnly = true;
private Handler mHandler = new Handler();
/**
* 因无限循环,所以以下大部分回调都可能多次调用。
*/
public interface OnDownloadListener {
void onEnter();
void onProgress(int fileLength, int downloadSize, float percent);
void onPause();
void onIOError();
void onNetworkError();
void onSpaceError();
void onExit(boolean isFinish);
}
private OnDownloadListener mListener = null;
/**
* 创建后即开始下载,不主动调用结束,就一直在下载
* 网络、空间出错时,会通过回调上报
* 注意:不因为出错而结束,如果想结束,要主动调用stop
*
* @param context
* @param listener
* 回调侦听,显示错误及进度等
* @param downloadUrl
* 下载地址
* @param savePath
* 文件存储全路径,包括路径和文件名(请保证路径存在,本程序不负责创建路径,只负责创建下载的文件)
*/
public DownloaderManager(Context context, OnDownloadListener listener,
String downloadUrl, String savePath) {
mContext = context;
mListener = listener;
MyLogI("downladUrl = " + downloadUrl);
MyLogI("savePath = " + savePath);
if (TextUtils.isEmpty(downloadUrl)) {
MyLogE("empty url");
onListenerExit(false);
return;
}
if (TextUtils.isEmpty(savePath)) {
MyLogE("empty savePath");
onListenerExit(false);
return;
}
getInfo(downloadUrl, savePath);
new Thread(new Runnable() {
@Override
public void run() {
try { // 延迟开启下载
Thread.sleep(100);
} catch (InterruptedException e) {
}
doDownload();
}
}).start();
}
// 继续
public void resume() {
isPause = false;
}
// 暂停
public void pause() {
isPause = true;
}
// 判断是否暂停
public boolean isPause() {
return isPause;
}
// 停止
public void stop() {
isStop = true;
}
// 判断是否停止
public boolean isStop() {
return isStop;
}
// 设置数据网络可下载
public void setWifiOnly(boolean wifiOnly) {
isWifiOnly = wifiOnly;
}
// 是否只有wifi下可下载
public boolean isWifiOnly() {
return isWifiOnly;
}
// ------ 获取下载信息 0 ------
public String getDownloadUrl() {
if (mDFI != null) {
return mDFI.mDownloadUrl;
}
return "";
}
public String getSavePath() {
if (mDFI != null) {
return mDFI.mSavePath;
}
return "";
}
public int getFileLength() {
if (mDFI != null) {
return mDFI.mFileLength;
}
return 0;
}
public int getDownloadSize() {
if (mDFI != null) {
return mDFI.mDownloadSize;
}
return 0;
}
// ------ 获取下载信息 1 ------
// 执行下载
private void doDownload() {
MyLogW("doDownload() enter");
onListenerEnter();
int count = 0;
int COUNT_MAX = 20;
InputStream is = null;
RandomAccessFile raf = null;
boolean isError = false;
while (true) {
try {
isError = false;
if (isStop) { // 结束下载
MyLogI("doDownload() isStop = " + isStop);
break;
}
// 判断是否暂停以及网络是否可用
if (!isPause && isNetworkAvailable()) {
// 打开连接
URLConnection urlConn = new URL(mDFI.mDownloadUrl).openConnection();
if (mDFI.mFileLength <= 0) { // 获取文件大小
mDFI.mFileLength = urlConn.getContentLength();
}
MyLogI("doDownload() mDFI.mFileLength = " + mDFI.mFileLength);
MyLogI("doDownload() mDFI.mDownloadSize = " + mDFI.mDownloadSize);
if (mDFI.mFileLength > 0 && isSpaceEnough()) {
File file = new File(mDFI.mSavePath);
if (file.exists()) { // 本地文件存在
MyLogI("doDownload() file.length() = " + file.length());
if (mDFI.mFileLength == file.length()) { // 已完成下载
mDFI.mDownloadSize = mDFI.mFileLength;
isStop = true;
MyLogW("doDownload() download complete!");
break;
} else { // 下载未完成
if (mDFI.mDownloadSize != file.length()) {
MyLogW("doDownload() file size error : delete");
file.delete(); // 文件大小不对,说明已被改变,直接删除重新下载
mDFI.mDownloadSize = 0;
}
}
}
is = urlConn.getInputStream();
raf = new RandomAccessFile(mDFI.mSavePath, "rw");
if (mDFI.mDownloadSize > 0) {
long byteCount = is.skip(mDFI.mDownloadSize);
MyLogE("doDownload() skip byteCount = " + byteCount + ", mDFI.mDownloadSize = " + mDFI.mDownloadSize);
if (byteCount == mDFI.mDownloadSize) {
raf.seek(mDFI.mDownloadSize);
} else {
isError = true;
}
}
if (!isError) {
int len = 0;
byte[] bytes = new byte[10240];
while (true) {
if (isStop) { // 结束下载
MyLogI("doDownload() isStop = " + isStop);
break;
}
isError = false;
// 判断网络是否可用
if (!isPause && !isNetworkAvailable()) {
isError = true;
}
// 判断空间是否足够
if (!isPause && !isSpaceEnough()) {
isError = true;
}
// 判断是否暂停或出错
if (!isPause && !isError) {
len = is.read(bytes);
if (len != (-1)) { // 未完成
raf.write(bytes, 0, len);
mDFI.mDownloadSize += len; // 改变下载大小
count ++;
if (count >= COUNT_MAX) {
count = 0;
float percent = ((int) ((mDFI.mDownloadSize / (float) mDFI.mFileLength) * 1000)) / (float) 10;
MyLogI("doDownload() download mDFI.mFileLength = " + mDFI.mFileLength
+ ", mDFI.mDownloadSize = " + mDFI.mDownloadSize
+ ", percent = " + percent);
onListenerProgress(mDFI.mFileLength, mDFI.mDownloadSize, percent);
}
} else {
if (mDFI.mDownloadSize == mDFI.mFileLength) { // 完成
isStop = true;
MyLogI("doDownload() download mDFI.mFileLength = " + mDFI.mFileLength
+ ", mDFI.mDownloadSize = " + mDFI.mDownloadSize);
MyLogW("doDownload() download complete now!");
onListenerProgress(mDFI.mFileLength, mDFI.mDownloadSize, 100);
} else { // 下载失败
MyLogE("doDownload() download mDFI.mFileLength = " + mDFI.mFileLength
+ ", mDFI.mDownloadSize = " + mDFI.mDownloadSize);
MyLogE("doDownload() error mDownloadSize != mFileLength");
mDFI.mDownloadSize = 0; // 设置重新下载
}
break;
}
} else if (isPause) {
MyLogW("doDownload() is pause");
onListenerPause();
}
if (!isStop) {
try { // 进入休眠,不能老占用资源
if (isPause || isError) {
Thread.sleep(3000); // 暂停或出错时,休眠时间长一些
} else { // 未出错时,休眠时间短些
Thread.sleep(10);
}
} catch (InterruptedException e) {
MyLogW("doDownload() InterruptedException");
}
}
}
}
}
} else if (isPause) {
MyLogW("doDownload() is pause");
onListenerPause();
}
} catch (IOException e) {
e.printStackTrace();
MyLogW("doDownload() IOException");
onListenerIOError();
} finally {
if (raf != null) {
try {
raf.close();
raf = null;
} catch (IOException e) {
e.printStackTrace();
MyLogW("doDownload() IOException");
onListenerIOError();
}
}
if (is != null) {
try {
is.close();
is = null;
} catch (IOException e) {
e.printStackTrace();
MyLogW("doDownload() IOException");
onListenerIOError();
}
}
}
if (!isStop) {
try { // 进入休眠,不能老占用资源
Thread.sleep(3000);
} catch (InterruptedException e) {
MyLogW("doDownload() InterruptedException");
}
}
}
saveInfo();
boolean isFinish = false;
if (mDFI != null) {
MyLogW("mDFI.mFileLength = " + mDFI.mFileLength +
", mDFI.mDownloadSize = " + mDFI.mDownloadSize);
if (mDFI.mFileLength > 0 && mDFI.mFileLength == mDFI.mDownloadSize) {
isFinish = true;
}
}
MyLogW("doDownload() exit isFinish = " + isFinish);
onListenerExit(isFinish);
}
// MD5
private String getMd5(String s) {
if (TextUtils.isEmpty(s)) {
return s;
}
try {
// Create MD5 Hash
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
for (int i = 0, v = 0; i < messageDigest.length; i++) {
v = 0xFF & messageDigest[i];
if (v < 16) {
hexString.append("0");
}
hexString.append(Integer.toHexString(v));
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
}
return s;
}
// 读取上次下载信息
private void getInfo(String downloadUrl, String savePath) {
// 初始化下载信息
if (mDFI == null) {
mDFI = new DownloadFileInfo();
}
mDFI.mDownloadUrl = downloadUrl;
mDFI.mSavePath = savePath;
mDFI.mFileLength = 0;
mDFI.mDownloadSize = 0;
// 获取保存信息
if (mPreferences == null) {
mPreferences = mContext.getSharedPreferences(KEY_SP, Context.MODE_PRIVATE);
}
JSONObject json = new JSONObject();
try {
json.put("url", downloadUrl);
json.put("path", savePath);
String jsonStr = mPreferences.getString(getMd5(json.toString()), "");
if (!TextUtils.isEmpty(jsonStr)) {
json = new JSONObject(jsonStr);
mDFI.mDownloadUrl = json.getString("url");
mDFI.mSavePath = json.getString("path");
mDFI.mFileLength = json.getInt("length");
mDFI.mDownloadSize = json.getInt("size");
}
} catch (JSONException e) {
}
MyLogI("mDFI.mDownloadUrl = " + mDFI.mDownloadUrl);
MyLogI("mDFI.mSavePath = " + mDFI.mSavePath);
MyLogI("mDFI.mFileLength = " + mDFI.mFileLength);
MyLogI("mDFI.mDownloadSize = " + mDFI.mDownloadSize);
}
private void saveInfo() {
// 初始化下载信息
if (mDFI == null) {
return;
}
// 保存信息
if (mPreferences == null) {
mPreferences = mContext.getSharedPreferences(KEY_SP, Context.MODE_PRIVATE);
}
JSONObject json = new JSONObject();
try {
json.put("url", mDFI.mDownloadUrl);
json.put("path", mDFI.mSavePath);
String jsonStr = json.toString();
json.put("length", mDFI.mFileLength);
json.put("size", mDFI.mDownloadSize);
Editor editor = mPreferences.edit();
if (mDFI.mFileLength == mDFI.mDownloadSize) {
editor.putString(getMd5(jsonStr), "");
} else {
editor.putString(getMd5(jsonStr), json.toString());
}
editor.commit();
} catch (JSONException e) {
}
}
// 获取网络制式
private static final String WIFI = "WIFI";
private static final String MOBILE = "MOBILE";
private String getNetworkType() {
String strNetworkType = "";
try { // 获取网络信息
NetworkInfo networkInfo = ((ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE))
.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
strNetworkType = WIFI; // WIFI
} else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
strNetworkType = MOBILE; // 数据网络
}
}
} catch (Throwable e) {
}
return strNetworkType;
}
// 网络是否可用
private boolean isNetworkAvailable() {
boolean isAvailable = false;
String networkType = getNetworkType();
if (TextUtils.isEmpty(networkType)) { // 无网络
} else if (TextUtils.equals(networkType, WIFI)) { // WIFI
isAvailable = true;
} else if (TextUtils.equals(networkType, MOBILE)) { // 数据网络
if (!isWifiOnly) {
isAvailable = true;
} else { // 人为设置数据网络是否可用于下载
String path = Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + "wifi_ex";
if (new File(path).exists()) {
isAvailable = true;
}
}
}
if (!isAvailable) {
MyLogW("isNetworkAvailable() isAvailable = " + isAvailable);
onListenerNetworkError();
}
return isAvailable;
}
// 获取空间大小
@SuppressWarnings("deprecation")
private long getVacantSpaceSize(String path) {
StatFs fileStats = new StatFs(path);
fileStats.restat(path);
long size = (long) fileStats.getAvailableBlocks() * (long) fileStats.getBlockSize();
return size;
}
// 空间富余量,即比要下载的文件大小多出多少空间,默认12MB
private long SPACE_MORE = 12 * 1024 * 1024;
// 设置空间富余量
public void setSpaceMore(long more) {
SPACE_MORE = more;
}
// 空间是否足够
private boolean isSpaceEnough() {
boolean isEnough = true;
// 获取sd卡剩余空间大小
long vacantSpace = getVacantSpaceSize(Environment.getExternalStorageDirectory()
.getAbsolutePath());
// 文件大小
int fileLength = 0;
// 完成下载大小
int downloadSize = 0;
// 初始化文件和下载大小
if (mDFI != null) {
fileLength = mDFI.mFileLength;
downloadSize = mDFI.mDownloadSize;
}
// 剩余空间比需要下载的文件大小多出富余大小以上,被认为是空间足够
if (fileLength + SPACE_MORE - downloadSize >= vacantSpace) {
isEnough = false;
}
// 人为设置空间是否足够
String path = Environment.getExternalStorageDirectory().getAbsolutePath() +
File.separator + "low_space";
if (new File(path).exists()) {
isEnough = false;
}
if (!isEnough) {
MyLogW("isSpaceEnough() false");
onListenerSpaceError();
}
return isEnough;
}
// ------ 侦听回调处理 0 ------
private void onListenerEnter() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onEnter();
}
}
});
}
}
private void onListenerProgress(final int fileLength, final int downloadSize,
final float percent) {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onProgress(fileLength, downloadSize, percent);
}
}
});
}
}
private void onListenerPause() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onPause();
}
}
});
}
}
private void onListenerIOError() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onIOError();
}
}
});
}
}
private void onListenerNetworkError() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onNetworkError();
}
}
});
}
}
private void onListenerSpaceError() {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onSpaceError();
}
}
});
}
}
private void onListenerExit(final boolean isFinish) {
if (mListener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mListener != null) {
mListener.onExit(isFinish);
}
}
});
}
}
// ------ 侦听回调处理 1 ------
// ------ 打印相关 0 ------
private void MyLogE(String info) {
android.util.Log.e(TAG, info);
}
private void MyLogW(String info) {
android.util.Log.w(TAG, info);
}
private boolean isInfoLog = false;
public void setIsInfoLog(boolean isLog) {
isInfoLog = isLog;
}
private void MyLogI(String info) {
if (isInfoLog) {
android.util.Log.i(TAG, info);
}
}
// ------ 打印相关 1 ------
}