修复网络很差时下载文件不完整的bug

pull/2/head
lyy 9 years ago
parent 259d9f6ed9
commit 71d70f6d66
  1. 6
      .idea/misc.xml
  2. 3
      app/src/main/java/com/example/arial/downloaddemo/MainActivity.java
  3. 149
      downloadutil/src/main/java/com/arialyy/downloadutil/DownLoadUtil.java
  4. 61
      downloadutil/src/main/java/com/arialyy/downloadutil/DownloadListener.java

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager"> <component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" /> <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" /> <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
@ -56,9 +59,6 @@
<component name="ProjectType"> <component name="ProjectType">
<option name="id" value="Android" /> <option name="id" value="Android" />
</component> </component>
<component name="SvnConfiguration">
<configuration>C:\Users\AriaL\AppData\Roaming\Subversion</configuration>
</component>
<component name="masterDetails"> <component name="masterDetails">
<states> <states>
<state key="ScopeChooserConfigurable.UI"> <state key="ScopeChooserConfigurable.UI">

@ -17,7 +17,6 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.arialyy.downloadutil.DownLoadUtil; import com.arialyy.downloadutil.DownLoadUtil;
import com.arialyy.downloadutil.DownloadListener;
import com.arialyy.downloadutil.Util; import com.arialyy.downloadutil.Util;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
@ -106,7 +105,7 @@ public class MainActivity extends AppCompatActivity {
private void start() { private void start() {
mUtil.download(this, mDownloadUrl, Environment.getExternalStorageDirectory().getPath() + "/test.apk" mUtil.download(this, mDownloadUrl, Environment.getExternalStorageDirectory().getPath() + "/test.apk"
, new DownloadListener() { , new DownLoadUtil.DownloadListener() {
long fileSize = 1; long fileSize = 1;
@Override @Override

@ -15,7 +15,6 @@ import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Properties; import java.util.Properties;
/** /**
* Created by lyy on 2015/8/25. * Created by lyy on 2015/8/25.
* 下载工具类 * 下载工具类
@ -23,7 +22,7 @@ import java.util.Properties;
public class DownLoadUtil { public class DownLoadUtil {
private static final String TAG = "DownLoadUtil"; private static final String TAG = "DownLoadUtil";
//下载监听 //下载监听
private IDownloadListener mListener; private DownloadListener mListener;
/** /**
* 线程数 * 线程数
*/ */
@ -40,10 +39,11 @@ public class DownLoadUtil {
boolean isNewTask = true; boolean isNewTask = true;
private int mCancelNum = 0; private int mCancelNum = 0;
private int mStopNum = 0; private int mStopNum = 0;
public DownLoadUtil() { public DownLoadUtil() {
} }
public DownloadListener getListener(){
return mListener;
}
/** /**
* 获取当前下载位置 * 获取当前下载位置
* *
@ -52,25 +52,21 @@ public class DownLoadUtil {
public long getCurrentLocation() { public long getCurrentLocation() {
return mCurrentLocation; return mCurrentLocation;
} }
public boolean isDownloading() { public boolean isDownloading() {
return isDownloading; return isDownloading;
} }
/** /**
* 取消下载 * 取消下载
*/ */
public void cancelDownload() { public void cancelDownload() {
isCancel = true; isCancel = true;
} }
/** /**
* 停止下载 * 停止下载
*/ */
public void stopDownload() { public void stopDownload() {
isStop = true; isStop = true;
} }
/** /**
* 多线程断点续传下载文件暂停和继续 * 多线程断点续传下载文件暂停和继续
* *
@ -99,7 +95,7 @@ public class DownLoadUtil {
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
mListener.onFail(); failDownload("下载失败,记录文件被删除");
return; return;
} }
new Thread(new Runnable() { new Thread(new Runnable() {
@ -111,13 +107,13 @@ public class DownLoadUtil {
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Charset", "UTF-8");
conn.setConnectTimeout(TIME_OUT); conn.setConnectTimeout(TIME_OUT * 4);
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"); conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
conn.connect(); conn.connect();
int len = conn.getContentLength(); int len = conn.getContentLength();
if (len < 0) { //网络被劫持时会出现这个问题 if (len < 0) { //网络被劫持时会出现这个问题
mListener.onFail(); failDownload("下载失败,网络被劫持");
return; return;
} }
int code = conn.getResponseCode(); int code = conn.getResponseCode();
@ -137,12 +133,15 @@ public class DownLoadUtil {
} else { } else {
for (int i = 0; i < THREAD_NUM; i++) { for (int i = 0; i < THREAD_NUM; i++) {
if (pro.getProperty(dFile.getName() + "_record_" + i) == null) { if (pro.getProperty(dFile.getName() + "_record_" + i) == null) {
Object state = pro.getProperty(dFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) {
continue;
}
isNewTask = true; isNewTask = true;
break; break;
} }
} }
} }
int blockSize = fileLength / THREAD_NUM; int blockSize = fileLength / THREAD_NUM;
SparseArray<Thread> tasks = new SparseArray<>(); SparseArray<Thread> tasks = new SparseArray<>();
int[] recordL = new int[THREAD_NUM]; int[] recordL = new int[THREAD_NUM];
@ -165,7 +164,6 @@ public class DownLoadUtil {
} }
mListener.onComplete(); mListener.onComplete();
isDownloading = false; isDownloading = false;
System.gc();
return; return;
} }
continue; continue;
@ -180,6 +178,8 @@ public class DownLoadUtil {
startL = r; startL = r;
recordL[rl] = i; recordL[rl] = i;
rl++; rl++;
}else {
isNewTask = true;
} }
if (isNewTask) { if (isNewTask) {
recordL[rl] = i; recordL[rl] = i;
@ -205,20 +205,21 @@ public class DownLoadUtil {
} }
} }
} else { } else {
Log.e(TAG, "下载失败,返回码:" + code); failDownload("下载失败,返回码:" + code);
isDownloading = false;
System.gc();
mListener.onFail();
} }
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "下载失败【downloadUrl:" + downloadUrl + "】\n【filePath:" + filePath + "】" + Util.getPrintException(e)); failDownload("下载失败【downloadUrl:" + downloadUrl + "】\n【filePath:" + filePath + "】" + Util.getPrintException(e));
isDownloading = false;
mListener.onFail();
} }
} }
}).start(); }).start();
} }
private void failDownload(String msg){
Log.e(TAG, msg);
isDownloading = false;
stopDownload();
mListener.onFail();
System.gc();
}
/** /**
* 多线程下载任务类,不能使用AsyncTask来进行多线程下载因为AsyncTask是串行执行的这种方式下载速度太慢了 * 多线程下载任务类,不能使用AsyncTask来进行多线程下载因为AsyncTask是串行执行的这种方式下载速度太慢了
*/ */
@ -226,14 +227,13 @@ public class DownLoadUtil {
private static final String TAG = "DownLoadTask"; private static final String TAG = "DownLoadTask";
private DownloadEntity dEntity; private DownloadEntity dEntity;
private String configFPath; private String configFPath;
public DownLoadTask(DownloadEntity downloadInfo) { public DownLoadTask(DownloadEntity downloadInfo) {
this.dEntity = downloadInfo; this.dEntity = downloadInfo;
configFPath = dEntity.context.getFilesDir().getPath() + "/temp/" + dEntity.tempFile.getName() + ".properties"; configFPath = dEntity.context.getFilesDir().getPath() + "/temp/" + dEntity.tempFile.getName() + ".properties";
} }
@Override @Override
public void run() { public void run() {
long currentLocation = 0;
try { try {
Log.d(TAG, "线程_" + dEntity.threadId + "_正在下载【" + "开始位置 : " + dEntity.startLocation + ",结束位置:" + dEntity.endLocation + "】"); Log.d(TAG, "线程_" + dEntity.threadId + "_正在下载【" + "开始位置 : " + dEntity.startLocation + ",结束位置:" + dEntity.endLocation + "】");
URL url = new URL(dEntity.downloadUrl); URL url = new URL(dEntity.downloadUrl);
@ -242,10 +242,10 @@ public class DownLoadUtil {
conn.setRequestProperty("Range", "bytes=" + dEntity.startLocation + "-" + dEntity.endLocation); conn.setRequestProperty("Range", "bytes=" + dEntity.startLocation + "-" + dEntity.endLocation);
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Charset", "UTF-8");
conn.setConnectTimeout(TIME_OUT); conn.setConnectTimeout(TIME_OUT * 4);
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"); conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
conn.setReadTimeout(2000); //设置读取流的等待时间,必须设置该参数 conn.setReadTimeout(TIME_OUT * 24); //设置读取流的等待时间,必须设置该参数
InputStream is = conn.getInputStream(); InputStream is = conn.getInputStream();
//创建可设置位置的文件 //创建可设置位置的文件
RandomAccessFile file = new RandomAccessFile(dEntity.tempFile, "rwd"); RandomAccessFile file = new RandomAccessFile(dEntity.tempFile, "rwd");
@ -254,17 +254,15 @@ public class DownLoadUtil {
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
int len; int len;
//当前子线程的下载位置 //当前子线程的下载位置
long currentLocation = dEntity.startLocation; currentLocation = dEntity.startLocation;
while ((len = is.read(buffer)) != -1) { while ((len = is.read(buffer)) != -1) {
if (isCancel) { if (isCancel) {
Log.d(TAG, "++++++++++ thread_" + dEntity.threadId + "_cancel ++++++++++"); Log.d(TAG, "++++++++++ thread_" + dEntity.threadId + "_cancel ++++++++++");
break; break;
} }
if (isStop) { if (isStop) {
break; break;
} }
//把下载数据数据写入文件 //把下载数据数据写入文件
file.write(buffer, 0, len); file.write(buffer, 0, len);
synchronized (DownLoadUtil.this) { synchronized (DownLoadUtil.this) {
@ -275,7 +273,6 @@ public class DownLoadUtil {
} }
file.close(); file.close();
is.close(); is.close();
if (isCancel) { if (isCancel) {
synchronized (DownLoadUtil.this) { synchronized (DownLoadUtil.this) {
mCancelNum++; mCancelNum++;
@ -284,7 +281,6 @@ public class DownLoadUtil {
if (configFile.exists()) { if (configFile.exists()) {
configFile.delete(); configFile.delete();
} }
if (dEntity.tempFile.exists()) { if (dEntity.tempFile.exists()) {
dEntity.tempFile.delete(); dEntity.tempFile.delete();
} }
@ -296,7 +292,6 @@ public class DownLoadUtil {
} }
return; return;
} }
//停止状态不需要删除记录文件 //停止状态不需要删除记录文件
if (isStop) { if (isStop) {
synchronized (DownLoadUtil.this) { synchronized (DownLoadUtil.this) {
@ -313,7 +308,6 @@ public class DownLoadUtil {
} }
return; return;
} }
Log.i(TAG, "线程【" + dEntity.threadId + "】下载完毕"); Log.i(TAG, "线程【" + dEntity.threadId + "】下载完毕");
writeConfig(dEntity.tempFile.getName() + "_state_" + dEntity.threadId, 1 + ""); writeConfig(dEntity.tempFile.getName() + "_state_" + dEntity.threadId, 1 + "");
mListener.onChildComplete(dEntity.endLocation); mListener.onChildComplete(dEntity.endLocation);
@ -323,25 +317,44 @@ public class DownLoadUtil {
if (configFile.exists()) { if (configFile.exists()) {
configFile.delete(); configFile.delete();
} }
mListener.onComplete();
isDownloading = false; isDownloading = false;
mListener.onComplete();
System.gc(); System.gc();
} }
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
e.printStackTrace(); e.printStackTrace();
isDownloading = false; isDownloading = false;
mListener.onFail(); synchronized (DownLoadUtil.this) {
try {
String location = String.valueOf(currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
failDownload("下载链接异常");
} catch (IOException e1) {
e1.printStackTrace();
}
}
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "下载失败【" + dEntity.downloadUrl + "】" + Util.getPrintException(e)); synchronized (DownLoadUtil.this) {
isDownloading = false; try {
mListener.onFail(); String location = String.valueOf(currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
failDownload("下载失败【" + dEntity.downloadUrl + "】" + Util.getPrintException(e));
} catch (IOException e1) {
e1.printStackTrace();
}
}
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "获取流失败" + Util.getPrintException(e)); synchronized (DownLoadUtil.this) {
isDownloading = false; try {
mListener.onFail(); String location = String.valueOf(currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
failDownload("获取流失败" + Util.getPrintException(e));
} catch (IOException e1) {
e1.printStackTrace();
}
}
} }
} }
/** /**
* 将记录写入到配置文件 * 将记录写入到配置文件
* *
@ -354,8 +367,6 @@ public class DownLoadUtil {
Util.saveConfig(configFile, pro); Util.saveConfig(configFile, pro);
} }
} }
/** /**
* 子线程下载信息类 * 子线程下载信息类
*/ */
@ -368,7 +379,6 @@ public class DownLoadUtil {
long endLocation; long endLocation;
File tempFile; File tempFile;
Context context; Context context;
public DownloadEntity(Context context, long fileSize, String downloadUrl, File file, int threadId, long startLocation, long endLocation) { public DownloadEntity(Context context, long fileSize, String downloadUrl, File file, int threadId, long startLocation, long endLocation) {
this.fileSize = fileSize; this.fileSize = fileSize;
this.downloadUrl = downloadUrl; this.downloadUrl = downloadUrl;
@ -380,5 +390,56 @@ public class DownLoadUtil {
} }
} }
public static class DownloadListener implements IDownloadListener {
@Override
public void onResume(long resumeLocation) {
}
@Override
public void onCancel() {
}
@Override
public void onFail() {
}
@Override
public void onPreDownload(HttpURLConnection connection) {
}
@Override
public void onProgress(long currentLocation) {
}
@Override
public void onChildComplete(long finishLocation) {
}
@Override
public void onStart(long startLocation) {
}
@Override
public void onChildResume(long resumeLocation) {
}
@Override
public void onStop(long stopLocation) {
} }
@Override
public void onComplete() {
}
}
}

@ -1,61 +0,0 @@
package com.arialyy.downloadutil;
import com.arialyy.downloadutil.inf.IDownloadListener;
import java.net.HttpURLConnection;
/**
* 下载监听
*/
public class DownloadListener implements IDownloadListener {
@Override
public void onResume(long resumeLocation) {
}
@Override
public void onCancel() {
}
@Override
public void onFail() {
}
@Override
public void onPreDownload(HttpURLConnection connection) {
}
@Override
public void onProgress(long currentLocation) {
}
@Override
public void onChildComplete(long finishLocation) {
}
@Override
public void onStart(long startLocation) {
}
@Override
public void onChildResume(long resumeLocation) {
}
@Override
public void onStop(long stopLocation) {
}
@Override
public void onComplete() {
}
}
Loading…
Cancel
Save