ftp下载
This commit is contained in:
@ -17,7 +17,7 @@ package com.arialyy.aria.core.download;
|
|||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import com.arialyy.aria.core.AriaManager;
|
import com.arialyy.aria.core.AriaManager;
|
||||||
import com.arialyy.aria.core.download.downloader.http.DownloadGroupUtil;
|
import com.arialyy.aria.core.download.downloader.DownloadGroupUtil;
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
|
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
|
||||||
import com.arialyy.aria.core.inf.AbsGroupTask;
|
import com.arialyy.aria.core.inf.AbsGroupTask;
|
||||||
import com.arialyy.aria.core.scheduler.ISchedulers;
|
import com.arialyy.aria.core.scheduler.ISchedulers;
|
||||||
|
@ -19,11 +19,9 @@ package com.arialyy.aria.core.download;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.arialyy.aria.core.AriaManager;
|
import com.arialyy.aria.core.AriaManager;
|
||||||
import com.arialyy.aria.core.download.downloader.ftp.FtpDownloadUtil;
|
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
|
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
|
||||||
import com.arialyy.aria.core.download.downloader.http.SimpleDownloadUtil;
|
import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil;
|
||||||
import com.arialyy.aria.core.inf.AbsNormalTask;
|
import com.arialyy.aria.core.inf.AbsNormalTask;
|
||||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
|
||||||
import com.arialyy.aria.core.inf.IEntity;
|
import com.arialyy.aria.core.inf.IEntity;
|
||||||
import com.arialyy.aria.core.scheduler.ISchedulers;
|
import com.arialyy.aria.core.scheduler.ISchedulers;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -43,11 +41,12 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity> {
|
|||||||
mOutHandler = outHandler;
|
mOutHandler = outHandler;
|
||||||
mContext = AriaManager.APP;
|
mContext = AriaManager.APP;
|
||||||
mListener = new DownloadListener(this, mOutHandler);
|
mListener = new DownloadListener(this, mOutHandler);
|
||||||
if (taskEntity.downloadType == AbsTaskEntity.HTTP) {
|
|
||||||
mUtil = new SimpleDownloadUtil(taskEntity, mListener);
|
mUtil = new SimpleDownloadUtil(taskEntity, mListener);
|
||||||
}else if (taskEntity.downloadType == AbsTaskEntity.FTP){
|
//if (taskEntity.downloadType == AbsTaskEntity.HTTP) {
|
||||||
mUtil = new FtpDownloadUtil(taskEntity, mListener);
|
// mUtil = new SimpleDownloadUtil(taskEntity, mListener);
|
||||||
}
|
//}else if (taskEntity.downloadType == AbsTaskEntity.FTP){
|
||||||
|
// mUtil = new FtpDownloadUtil(taskEntity, mListener);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,10 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.arialyy.aria.core.download;
|
package com.arialyy.aria.core.download;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lyy on 2016/12/5.
|
* Created by lyy on 2016/12/5.
|
||||||
@ -32,7 +35,7 @@ public class FtpDownloadTarget extends DownloadTarget {
|
|||||||
* @param port ftp端口号
|
* @param port ftp端口号
|
||||||
*/
|
*/
|
||||||
FtpDownloadTarget(String serverIp, String port, String filePath, String targetName) {
|
FtpDownloadTarget(String serverIp, String port, String filePath, String targetName) {
|
||||||
this(serverIp + ":" + port + "/" + filePath, targetName);
|
this("ftp://" + serverIp + ":" + port + "/" + filePath, targetName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,6 +49,46 @@ public class FtpDownloadTarget extends DownloadTarget {
|
|||||||
mEntity.setFileName(url.substring(lastIndex + 1, url.length()));
|
mEntity.setFileName(url.substring(lastIndex + 1, url.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置文件保存文件夹路径
|
||||||
|
* 关于文件名:
|
||||||
|
* 1、如果保存路径是该文件的保存路径,如:/mnt/sdcard/file.zip,则使用路径中的文件名file.zip
|
||||||
|
* 2、如果保存路径是文件夹路径,如:/mnt/sdcard/,则使用FTP服务器该文件的文件名
|
||||||
|
*
|
||||||
|
* @param downloadPath 路径必须为文件路径,不能为文件夹路径
|
||||||
|
*/
|
||||||
|
@Override public FtpDownloadTarget setDownloadPath(@NonNull String downloadPath) {
|
||||||
|
if (TextUtils.isEmpty(downloadPath)) {
|
||||||
|
throw new IllegalArgumentException("文件保持路径不能为null");
|
||||||
|
}
|
||||||
|
File file = new File(downloadPath);
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
downloadPath += mEntity.getFileName();
|
||||||
|
}
|
||||||
|
if (!downloadPath.equals(mEntity.getDownloadPath())) {
|
||||||
|
File oldFile = new File(mEntity.getDownloadPath());
|
||||||
|
File newFile = new File(downloadPath);
|
||||||
|
if (TextUtils.isEmpty(mEntity.getDownloadPath()) || oldFile.renameTo(newFile)) {
|
||||||
|
mEntity.setDownloadPath(downloadPath);
|
||||||
|
mEntity.setFileName(newFile.getName());
|
||||||
|
mTaskEntity.key = downloadPath;
|
||||||
|
mEntity.update();
|
||||||
|
mTaskEntity.update();
|
||||||
|
CommonUtil.renameDownloadConfig(oldFile.getName(), newFile.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置字符编码
|
||||||
|
*/
|
||||||
|
public FtpDownloadTarget charSet(String charSet) {
|
||||||
|
if (TextUtils.isEmpty(charSet)) return this;
|
||||||
|
mTaskEntity.charSet = charSet;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ftp 用户登录信息
|
* ftp 用户登录信息
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import com.arialyy.aria.core.AriaManager;
|
||||||
|
import com.arialyy.aria.core.download.DownloadEntity;
|
||||||
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2017/1/18.
|
||||||
|
* 下载线程
|
||||||
|
*/
|
||||||
|
abstract class AbsThreadTask implements Runnable {
|
||||||
|
private final String TAG = "AbsThreadTask";
|
||||||
|
long mChildCurrentLocation = 0, mSleepTime = 0;
|
||||||
|
int mBufSize;
|
||||||
|
String mConfigFPath;
|
||||||
|
SubThreadConfig mConfig;
|
||||||
|
IDownloadListener mListener;
|
||||||
|
StateConstance STATE;
|
||||||
|
DownloadEntity mEntity;
|
||||||
|
DownloadTaskEntity mTaskEntity;
|
||||||
|
|
||||||
|
AbsThreadTask(StateConstance constance, IDownloadListener listener,
|
||||||
|
SubThreadConfig downloadInfo) {
|
||||||
|
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
|
||||||
|
STATE = constance;
|
||||||
|
STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();
|
||||||
|
STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut();
|
||||||
|
mListener = listener;
|
||||||
|
mConfig = downloadInfo;
|
||||||
|
mTaskEntity = mConfig.DOWNLOAD_TASK_ENTITY;
|
||||||
|
mEntity = mTaskEntity.getEntity();
|
||||||
|
if (mConfig.IS_SUPPORT_BREAK_POINT) {
|
||||||
|
mConfigFPath = downloadInfo.CONFIG_FILE_PATH;
|
||||||
|
}
|
||||||
|
mBufSize = manager.getDownloadConfig().getBuffSize();
|
||||||
|
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMaxSpeed(double maxSpeed) {
|
||||||
|
if (-0.9999 < maxSpeed && maxSpeed < 0.00001) {
|
||||||
|
mSleepTime = 0;
|
||||||
|
} else {
|
||||||
|
BigDecimal db = new BigDecimal(
|
||||||
|
((mBufSize / 1024) * (filterVersion() ? 1 : STATE.THREAD_NUM) / maxSpeed) * 1000);
|
||||||
|
mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean filterVersion() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止下载
|
||||||
|
*/
|
||||||
|
void stop() {
|
||||||
|
synchronized (AriaManager.LOCK) {
|
||||||
|
try {
|
||||||
|
if (mConfig.IS_SUPPORT_BREAK_POINT) {
|
||||||
|
STATE.STOP_NUM++;
|
||||||
|
Log.d(TAG, "任务【"
|
||||||
|
+ mConfig.TEMP_FILE.getName()
|
||||||
|
+ "】thread__"
|
||||||
|
+ mConfig.THREAD_ID
|
||||||
|
+ "__停止, stop location ==> "
|
||||||
|
+ mChildCurrentLocation);
|
||||||
|
writeConfig(false, mChildCurrentLocation);
|
||||||
|
if (STATE.isStop()) {
|
||||||
|
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
|
||||||
|
STATE.isDownloading = false;
|
||||||
|
mListener.onStop(STATE.CURRENT_LOCATION);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
|
||||||
|
STATE.isDownloading = false;
|
||||||
|
mListener.onStop(STATE.CURRENT_LOCATION);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载中
|
||||||
|
*/
|
||||||
|
void progress(long len) {
|
||||||
|
synchronized (AriaManager.LOCK) {
|
||||||
|
mChildCurrentLocation += len;
|
||||||
|
STATE.CURRENT_LOCATION += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消下载
|
||||||
|
*/
|
||||||
|
void cancel() {
|
||||||
|
synchronized (AriaManager.LOCK) {
|
||||||
|
if (mConfig.IS_SUPPORT_BREAK_POINT) {
|
||||||
|
STATE.CANCEL_NUM++;
|
||||||
|
Log.d(TAG,
|
||||||
|
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消下载");
|
||||||
|
if (STATE.isCancel()) {
|
||||||
|
File configFile = new File(mConfigFPath);
|
||||||
|
if (configFile.exists()) {
|
||||||
|
configFile.delete();
|
||||||
|
}
|
||||||
|
if (mConfig.TEMP_FILE.exists()) {
|
||||||
|
mConfig.TEMP_FILE.delete();
|
||||||
|
}
|
||||||
|
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消");
|
||||||
|
STATE.isDownloading = false;
|
||||||
|
mListener.onCancel();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消");
|
||||||
|
STATE.isDownloading = false;
|
||||||
|
mListener.onCancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载失败
|
||||||
|
*/
|
||||||
|
void failDownload(long currentLocation, String msg, Exception ex) {
|
||||||
|
synchronized (AriaManager.LOCK) {
|
||||||
|
try {
|
||||||
|
STATE.FAIL_NUM++;
|
||||||
|
STATE.isDownloading = false;
|
||||||
|
STATE.isStop = true;
|
||||||
|
if (ex != null) {
|
||||||
|
Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
|
||||||
|
}
|
||||||
|
if (mConfig.IS_SUPPORT_BREAK_POINT) {
|
||||||
|
writeConfig(false, currentLocation);
|
||||||
|
if (STATE.isFail()) {
|
||||||
|
Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】下载失败");
|
||||||
|
mListener.onFail();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】下载失败");
|
||||||
|
mListener.onFail();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将记录写入到配置文件
|
||||||
|
*/
|
||||||
|
void writeConfig(boolean isComplete, long record) throws IOException {
|
||||||
|
synchronized (AriaManager.LOCK) {
|
||||||
|
String key = null, value = null;
|
||||||
|
if (0 < record && record < mConfig.END_LOCATION) {
|
||||||
|
key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID;
|
||||||
|
value = String.valueOf(record);
|
||||||
|
} else if (record >= mConfig.END_LOCATION || isComplete) {
|
||||||
|
key = mConfig.TEMP_FILE.getName() + "_state_" + mConfig.THREAD_ID;
|
||||||
|
value = "1";
|
||||||
|
}
|
||||||
|
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
||||||
|
File configFile = new File(mConfigFPath);
|
||||||
|
Properties pro = CommonUtil.loadConfig(configFile);
|
||||||
|
pro.setProperty(key, value);
|
||||||
|
CommonUtil.saveConfig(configFile, pro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
package com.arialyy.aria.core.download.downloader;
|
|
||||||
|
|
||||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 子线程下载信息类
|
|
||||||
*/
|
|
||||||
public class ChildThreadConfigEntity {
|
|
||||||
//线程Id
|
|
||||||
public int THREAD_ID;
|
|
||||||
//下载文件大小
|
|
||||||
public long FILE_SIZE;
|
|
||||||
//子线程启动下载位置
|
|
||||||
public long START_LOCATION;
|
|
||||||
//子线程结束下载位置
|
|
||||||
public long END_LOCATION;
|
|
||||||
//下载路径
|
|
||||||
public File TEMP_FILE;
|
|
||||||
public String DOWNLOAD_URL;
|
|
||||||
public String CONFIG_FILE_PATH;
|
|
||||||
public DownloadTaskEntity DOWNLOAD_TASK_ENTITY;
|
|
||||||
public boolean IS_SUPPORT_BREAK_POINT = true;
|
|
||||||
}
|
|
@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.arialyy.aria.core.download.downloader.http;
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
import com.arialyy.aria.util.SSLContextUtil;
|
import com.arialyy.aria.util.SSLContextUtil;
|
@ -13,15 +13,12 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.arialyy.aria.core.download.downloader.http;
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import com.arialyy.aria.core.download.DownloadEntity;
|
import com.arialyy.aria.core.download.DownloadEntity;
|
||||||
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
|
||||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadGroupListener;
|
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadListener;
|
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
|
|
||||||
import com.arialyy.aria.core.inf.IEntity;
|
import com.arialyy.aria.core.inf.IEntity;
|
||||||
import com.arialyy.aria.orm.DbEntity;
|
import com.arialyy.aria.orm.DbEntity;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
@ -78,7 +75,7 @@ public class DownloadGroupUtil implements IDownloadUtil {
|
|||||||
/**
|
/**
|
||||||
* 文件信息回调组
|
* 文件信息回调组
|
||||||
*/
|
*/
|
||||||
private SparseArray<FileInfoThread.OnFileInfoCallback> mFileInfoCallbacks = new SparseArray<>();
|
private SparseArray<OnFileInfoCallback> mFileInfoCallbacks = new SparseArray<>();
|
||||||
/**
|
/**
|
||||||
* 该任务组对应的所有任务
|
* 该任务组对应的所有任务
|
||||||
*/
|
*/
|
||||||
@ -214,11 +211,11 @@ public class DownloadGroupUtil implements IDownloadUtil {
|
|||||||
/**
|
/**
|
||||||
* 创建文件信息获取线程
|
* 创建文件信息获取线程
|
||||||
*/
|
*/
|
||||||
private FileInfoThread createFileInfoThread(DownloadTaskEntity taskEntity) {
|
private HttpFileInfoThread createFileInfoThread(DownloadTaskEntity taskEntity) {
|
||||||
FileInfoThread.OnFileInfoCallback callback = mFileInfoCallbacks.get(taskEntity.hashCode());
|
OnFileInfoCallback callback = mFileInfoCallbacks.get(taskEntity.hashCode());
|
||||||
|
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
callback = new FileInfoThread.OnFileInfoCallback() {
|
callback = new OnFileInfoCallback() {
|
||||||
int failNum = 0;
|
int failNum = 0;
|
||||||
|
|
||||||
@Override public void onComplete(String url, int code) {
|
@Override public void onComplete(String url, int code) {
|
||||||
@ -255,7 +252,7 @@ public class DownloadGroupUtil implements IDownloadUtil {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return new FileInfoThread(taskEntity, callback);
|
return new HttpFileInfoThread(taskEntity, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeTimer(boolean isRunning) {
|
private void closeTimer(boolean isRunning) {
|
@ -13,7 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.arialyy.aria.core.download.downloader.http;
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -21,10 +21,7 @@ import android.util.SparseArray;
|
|||||||
import com.arialyy.aria.core.AriaManager;
|
import com.arialyy.aria.core.AriaManager;
|
||||||
import com.arialyy.aria.core.download.DownloadEntity;
|
import com.arialyy.aria.core.download.DownloadEntity;
|
||||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
import com.arialyy.aria.core.download.downloader.ChildThreadConfigEntity;
|
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadListener;
|
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
|
|
||||||
import com.arialyy.aria.core.download.downloader.StateConstance;
|
|
||||||
import com.arialyy.aria.orm.DbEntity;
|
import com.arialyy.aria.orm.DbEntity;
|
||||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
@ -53,7 +50,7 @@ class Downloader implements Runnable, IDownloadUtil {
|
|||||||
private boolean isNewTask = true;
|
private boolean isNewTask = true;
|
||||||
private int mThreadNum, mRealThreadNum;
|
private int mThreadNum, mRealThreadNum;
|
||||||
private StateConstance mConstance;
|
private StateConstance mConstance;
|
||||||
private SparseArray<Runnable> mTask = new SparseArray<>();
|
private SparseArray<AbsThreadTask> mTask = new SparseArray<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小于1m的文件不启用多线程
|
* 小于1m的文件不启用多线程
|
||||||
@ -69,10 +66,9 @@ class Downloader implements Runnable, IDownloadUtil {
|
|||||||
mConstance = new StateConstance();
|
mConstance = new StateConstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override public void setMaxSpeed(double maxSpeed) {
|
||||||
public void setMaxSpeed(double maxSpeed) {
|
|
||||||
for (int i = 0; i < mThreadNum; i++) {
|
for (int i = 0; i < mThreadNum; i++) {
|
||||||
HttpThreadTask task = (HttpThreadTask) mTask.get(i);
|
AbsThreadTask task = mTask.get(i);
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
task.setMaxSpeed(maxSpeed);
|
task.setMaxSpeed(maxSpeed);
|
||||||
}
|
}
|
||||||
@ -155,7 +151,7 @@ class Downloader implements Runnable, IDownloadUtil {
|
|||||||
mFixedThreadPool.shutdown();
|
mFixedThreadPool.shutdown();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < mThreadNum; i++) {
|
for (int i = 0; i < mThreadNum; i++) {
|
||||||
HttpThreadTask task = (HttpThreadTask) mTask.get(i);
|
AbsThreadTask task = mTask.get(i);
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
task.cancel();
|
task.cancel();
|
||||||
}
|
}
|
||||||
@ -172,7 +168,7 @@ class Downloader implements Runnable, IDownloadUtil {
|
|||||||
mFixedThreadPool.shutdown();
|
mFixedThreadPool.shutdown();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < mThreadNum; i++) {
|
for (int i = 0; i < mThreadNum; i++) {
|
||||||
HttpThreadTask task = (HttpThreadTask) mTask.get(i);
|
AbsThreadTask task = mTask.get(i);
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
task.stop();
|
task.stop();
|
||||||
}
|
}
|
||||||
@ -285,18 +281,19 @@ class Downloader implements Runnable, IDownloadUtil {
|
|||||||
* 创建单线程任务
|
* 创建单线程任务
|
||||||
*/
|
*/
|
||||||
private void addSingleTask(int i, long startL, long endL, long fileLength) {
|
private void addSingleTask(int i, long startL, long endL, long fileLength) {
|
||||||
ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
|
SubThreadConfig config = new SubThreadConfig();
|
||||||
entity.FILE_SIZE = fileLength;
|
config.FILE_SIZE = fileLength;
|
||||||
entity.DOWNLOAD_URL =
|
config.DOWNLOAD_URL =
|
||||||
mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl();
|
mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl();
|
||||||
entity.TEMP_FILE = mTempFile;
|
config.TEMP_FILE = mTempFile;
|
||||||
entity.THREAD_ID = i;
|
config.THREAD_ID = i;
|
||||||
entity.START_LOCATION = startL;
|
config.START_LOCATION = startL;
|
||||||
entity.END_LOCATION = endL;
|
config.END_LOCATION = endL;
|
||||||
entity.CONFIG_FILE_PATH = mConfigFile.getPath();
|
config.CONFIG_FILE_PATH = mConfigFile.getPath();
|
||||||
entity.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP;
|
config.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP;
|
||||||
entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
|
config.DOWNLOAD_TASK_ENTITY = mTaskEntity;
|
||||||
HttpThreadTask task = new HttpThreadTask(mConstance, mListener, entity);
|
AbsThreadTask task = createThreadTask(config);
|
||||||
|
if (task == null) return;
|
||||||
mTask.put(i, task);
|
mTask.put(i, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,25 +393,36 @@ class Downloader implements Runnable, IDownloadUtil {
|
|||||||
* 处理不支持断点的下载
|
* 处理不支持断点的下载
|
||||||
*/
|
*/
|
||||||
private void handleNoSupportBreakpointDownload() {
|
private void handleNoSupportBreakpointDownload() {
|
||||||
ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
|
SubThreadConfig config = new SubThreadConfig();
|
||||||
long len = mEntity.getFileSize();
|
long len = mEntity.getFileSize();
|
||||||
entity.FILE_SIZE = len;
|
config.FILE_SIZE = len;
|
||||||
entity.DOWNLOAD_URL =
|
config.DOWNLOAD_URL =
|
||||||
mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl();
|
mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl();
|
||||||
entity.TEMP_FILE = mTempFile;
|
config.TEMP_FILE = mTempFile;
|
||||||
entity.THREAD_ID = 0;
|
config.THREAD_ID = 0;
|
||||||
entity.START_LOCATION = 0;
|
config.START_LOCATION = 0;
|
||||||
entity.END_LOCATION = entity.FILE_SIZE;
|
config.END_LOCATION = config.FILE_SIZE;
|
||||||
entity.CONFIG_FILE_PATH = mConfigFile.getPath();
|
config.CONFIG_FILE_PATH = mConfigFile.getPath();
|
||||||
entity.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP;
|
config.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP;
|
||||||
entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
|
config.DOWNLOAD_TASK_ENTITY = mTaskEntity;
|
||||||
HttpThreadTask task = new HttpThreadTask(mConstance, mListener, entity);
|
AbsThreadTask task = createThreadTask(config);
|
||||||
|
if (task == null) return;
|
||||||
mTask.put(0, task);
|
mTask.put(0, task);
|
||||||
mFixedThreadPool.execute(task);
|
mFixedThreadPool.execute(task);
|
||||||
mListener.onPostPre(len);
|
mListener.onPostPre(len);
|
||||||
mListener.onStart(0);
|
mListener.onStart(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AbsThreadTask createThreadTask(SubThreadConfig config) {
|
||||||
|
switch (mTaskEntity.downloadType) {
|
||||||
|
case AbsTaskEntity.FTP:
|
||||||
|
return new FtpThreadTask(mConstance, mListener, config);
|
||||||
|
case AbsTaskEntity.HTTP:
|
||||||
|
return new HttpThreadTask(mConstance, mListener, config);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private void failDownload(String errorMsg) {
|
private void failDownload(String errorMsg) {
|
||||||
closeTimer();
|
closeTimer();
|
||||||
Log.e(TAG, errorMsg);
|
Log.e(TAG, errorMsg);
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import com.arialyy.aria.core.AriaManager;
|
||||||
|
import com.arialyy.aria.core.download.DownloadEntity;
|
||||||
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.apache.commons.net.ftp.FTP;
|
||||||
|
import org.apache.commons.net.ftp.FTPClient;
|
||||||
|
import org.apache.commons.net.ftp.FTPFile;
|
||||||
|
import org.apache.commons.net.ftp.FTPReply;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/7/25.
|
||||||
|
* 获取ftp文件信息
|
||||||
|
*/
|
||||||
|
class FtpFileInfoThread implements Runnable {
|
||||||
|
|
||||||
|
private final String TAG = "HttpFileInfoThread";
|
||||||
|
private DownloadEntity mEntity;
|
||||||
|
private DownloadTaskEntity mTaskEntity;
|
||||||
|
private int mConnectTimeOut;
|
||||||
|
private OnFileInfoCallback mCallback;
|
||||||
|
|
||||||
|
FtpFileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) {
|
||||||
|
this.mTaskEntity = taskEntity;
|
||||||
|
mEntity = taskEntity.getEntity();
|
||||||
|
mConnectTimeOut =
|
||||||
|
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
|
||||||
|
mCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void run() {
|
||||||
|
FTPClient client = null;
|
||||||
|
try {
|
||||||
|
client = new FTPClient();
|
||||||
|
//ip和端口
|
||||||
|
String[] temp = mEntity.getDownloadUrl().split("/");
|
||||||
|
String[] pp = temp[2].split(":");
|
||||||
|
//String dir = temp[temp.length - 2];
|
||||||
|
String fileName = temp[temp.length - 1];
|
||||||
|
client.connect(pp[0], Integer.parseInt(pp[1]));
|
||||||
|
if (!TextUtils.isEmpty(mTaskEntity.account)) {
|
||||||
|
client.login(mTaskEntity.userName, mTaskEntity.userPw);
|
||||||
|
} else {
|
||||||
|
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
|
||||||
|
}
|
||||||
|
int reply = client.getReplyCode();
|
||||||
|
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||||
|
client.disconnect();
|
||||||
|
failDownload("无法连接到ftp服务器,错误码为:" + reply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.setDataTimeout(mConnectTimeOut);
|
||||||
|
client.enterLocalPassiveMode();
|
||||||
|
client.setFileType(FTP.BINARY_FILE_TYPE);
|
||||||
|
FTPFile[] files =
|
||||||
|
client.listFiles(CommonUtil.strCharSetConvert(fileName, mTaskEntity.charSet));
|
||||||
|
long size = getFileSize(files, client, fileName);
|
||||||
|
mEntity.setFileSize(size);
|
||||||
|
mTaskEntity.code = reply;
|
||||||
|
mEntity.update();
|
||||||
|
mTaskEntity.update();
|
||||||
|
mCallback.onComplete(mEntity.getDownloadUrl(), reply);
|
||||||
|
} catch (IOException e) {
|
||||||
|
failDownload(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
if (client != null) {
|
||||||
|
try {
|
||||||
|
client.logout();
|
||||||
|
client.disconnect();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历FTP服务器上对应文件或文件夹大小
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
|
||||||
|
long size = 0;
|
||||||
|
String path = dirName + "/";
|
||||||
|
for (FTPFile file : files) {
|
||||||
|
if (file.isFile()) {
|
||||||
|
size += file.getSize();
|
||||||
|
} else {
|
||||||
|
size += getFileSize(client.listFiles(
|
||||||
|
CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
|
||||||
|
path + file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void failDownload(String errorMsg) {
|
||||||
|
Log.e(TAG, errorMsg);
|
||||||
|
if (mCallback != null) {
|
||||||
|
mCallback.onFail(mEntity.getDownloadUrl(), errorMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import org.apache.commons.net.ftp.FTP;
|
||||||
|
import org.apache.commons.net.ftp.FTPClient;
|
||||||
|
import org.apache.commons.net.ftp.FTPFile;
|
||||||
|
import org.apache.commons.net.ftp.FTPReply;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/7/24.
|
||||||
|
* Ftp下载任务
|
||||||
|
*/
|
||||||
|
class FtpThreadTask extends AbsThreadTask {
|
||||||
|
private final String TAG = "FtpThreadTask";
|
||||||
|
|
||||||
|
FtpThreadTask(StateConstance constance, IDownloadListener listener,
|
||||||
|
SubThreadConfig downloadInfo) {
|
||||||
|
super(constance, listener, downloadInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void run() {
|
||||||
|
FTPClient client = null;
|
||||||
|
InputStream is = null;
|
||||||
|
BufferedRandomAccessFile file = null;
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "任务【"
|
||||||
|
+ mConfig.TEMP_FILE.getName()
|
||||||
|
+ "】线程__"
|
||||||
|
+ mConfig.THREAD_ID
|
||||||
|
+ "__开始下载【开始位置 : "
|
||||||
|
+ mConfig.START_LOCATION
|
||||||
|
+ ",结束位置:"
|
||||||
|
+ mConfig.END_LOCATION
|
||||||
|
+ "】");
|
||||||
|
client = new FTPClient();
|
||||||
|
//ip和端口
|
||||||
|
String[] temp = mEntity.getDownloadUrl().split("/");
|
||||||
|
String[] pp = temp[2].split(":");
|
||||||
|
//String dir = temp[temp.length - 2];
|
||||||
|
String fileName = temp[temp.length - 1];
|
||||||
|
client.connect(pp[0], Integer.parseInt(pp[1]));
|
||||||
|
if (!TextUtils.isEmpty(mTaskEntity.account)) {
|
||||||
|
client.login(mTaskEntity.userName, mTaskEntity.userPw);
|
||||||
|
} else {
|
||||||
|
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
|
||||||
|
}
|
||||||
|
int reply = client.getReplyCode();
|
||||||
|
if (!FTPReply.isPositiveCompletion(reply)) {
|
||||||
|
client.disconnect();
|
||||||
|
failDownload(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.setDataTimeout(STATE.READ_TIME_OUT);
|
||||||
|
client.enterLocalPassiveMode();
|
||||||
|
client.setFileType(FTP.BINARY_FILE_TYPE);
|
||||||
|
client.setRestartOffset(mConfig.START_LOCATION);
|
||||||
|
is = client.retrieveFileStream(fileName);
|
||||||
|
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
|
||||||
|
file.seek(mConfig.START_LOCATION);
|
||||||
|
byte[] buffer = new byte[mBufSize];
|
||||||
|
int len;
|
||||||
|
//当前子线程的下载位置
|
||||||
|
mChildCurrentLocation = mConfig.START_LOCATION;
|
||||||
|
//TODO: 2017/7/25 隐藏问题,速度太快(20m/s)或文件太小,秒下,会出现 ftp Connection reset by peer 问题
|
||||||
|
while ((len = is.read(buffer)) != -1) {
|
||||||
|
if (STATE.isCancel) break;
|
||||||
|
if (STATE.isStop) break;
|
||||||
|
if (mSleepTime > 0) Thread.sleep(mSleepTime);
|
||||||
|
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) {
|
||||||
|
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation);
|
||||||
|
file.write(buffer, 0, len);
|
||||||
|
progress(len);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
file.write(buffer, 0, len);
|
||||||
|
progress(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (STATE.isCancel || STATE.isStop) return;
|
||||||
|
if (client.completePendingCommand()) {
|
||||||
|
Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
|
||||||
|
writeConfig(true, 1);
|
||||||
|
STATE.COMPLETE_THREAD_NUM++;
|
||||||
|
if (STATE.isComplete()) {
|
||||||
|
File configFile = new File(mConfigFPath);
|
||||||
|
if (configFile.exists()) {
|
||||||
|
configFile.delete();
|
||||||
|
}
|
||||||
|
STATE.isDownloading = false;
|
||||||
|
mListener.onComplete();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
is.close();
|
||||||
|
Log.d(TAG, "SUCCESS");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
failDownload(mChildCurrentLocation, "下载失败【" + mConfig.DOWNLOAD_URL + "】", e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
failDownload(mChildCurrentLocation, "获取流失败", e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (client != null && client.isConnected()) {
|
||||||
|
//client.logout();
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,13 +13,14 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package com.arialyy.aria.core.download.downloader.http;
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.arialyy.aria.core.AriaManager;
|
import com.arialyy.aria.core.AriaManager;
|
||||||
import com.arialyy.aria.core.download.DownloadEntity;
|
import com.arialyy.aria.core.download.DownloadEntity;
|
||||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
|
import com.arialyy.aria.core.download.downloader.ConnectionHelp;
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
@ -29,30 +30,15 @@ import java.net.URLDecoder;
|
|||||||
/**
|
/**
|
||||||
* 下载文件信息获取
|
* 下载文件信息获取
|
||||||
*/
|
*/
|
||||||
class FileInfoThread implements Runnable {
|
class HttpFileInfoThread implements Runnable {
|
||||||
private final String TAG = "FileInfoThread";
|
private final String TAG = "HttpFileInfoThread";
|
||||||
private DownloadEntity mEntity;
|
private DownloadEntity mEntity;
|
||||||
private DownloadTaskEntity mTaskEntity;
|
private DownloadTaskEntity mTaskEntity;
|
||||||
private int mConnectTimeOut;
|
private int mConnectTimeOut;
|
||||||
private OnFileInfoCallback onFileInfoListener;
|
private OnFileInfoCallback onFileInfoListener;
|
||||||
|
|
||||||
interface OnFileInfoCallback {
|
|
||||||
/**
|
|
||||||
* 处理完成
|
|
||||||
*
|
|
||||||
* @param code 状态码
|
|
||||||
*/
|
|
||||||
void onComplete(String url, int code);
|
|
||||||
|
|
||||||
/**
|
HttpFileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) {
|
||||||
* 请求失败
|
|
||||||
*
|
|
||||||
* @param errorMsg 错误信息
|
|
||||||
*/
|
|
||||||
void onFail(String url, String errorMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) {
|
|
||||||
this.mTaskEntity = taskEntity;
|
this.mTaskEntity = taskEntity;
|
||||||
mEntity = taskEntity.getEntity();
|
mEntity = taskEntity.getEntity();
|
||||||
mConnectTimeOut =
|
mConnectTimeOut =
|
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2017/1/18.
|
||||||
|
* 下载线程
|
||||||
|
*/
|
||||||
|
final class HttpThreadTask extends AbsThreadTask {
|
||||||
|
private final String TAG = "HttpThreadTask";
|
||||||
|
|
||||||
|
HttpThreadTask(StateConstance constance, IDownloadListener listener,
|
||||||
|
SubThreadConfig downloadInfo) {
|
||||||
|
super(constance, listener, downloadInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void run() {
|
||||||
|
HttpURLConnection conn = null;
|
||||||
|
InputStream is = null;
|
||||||
|
BufferedRandomAccessFile file = null;
|
||||||
|
try {
|
||||||
|
URL url = new URL(mConfig.DOWNLOAD_URL);
|
||||||
|
conn = ConnectionHelp.handleConnection(url);
|
||||||
|
if (mConfig.IS_SUPPORT_BREAK_POINT) {
|
||||||
|
Log.d(TAG, "任务【"
|
||||||
|
+ mConfig.TEMP_FILE.getName()
|
||||||
|
+ "】线程__"
|
||||||
|
+ mConfig.THREAD_ID
|
||||||
|
+ "__开始下载【开始位置 : "
|
||||||
|
+ mConfig.START_LOCATION
|
||||||
|
+ ",结束位置:"
|
||||||
|
+ mConfig.END_LOCATION
|
||||||
|
+ "】");
|
||||||
|
//在头里面请求下载开始位置和结束位置
|
||||||
|
conn.setRequestProperty("Range",
|
||||||
|
"bytes=" + mConfig.START_LOCATION + "-" + (mConfig.END_LOCATION - 1));
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "该下载不支持断点");
|
||||||
|
}
|
||||||
|
conn = ConnectionHelp.setConnectParam(mConfig.DOWNLOAD_TASK_ENTITY, conn);
|
||||||
|
conn.setConnectTimeout(STATE.CONNECT_TIME_OUT);
|
||||||
|
conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数
|
||||||
|
is = conn.getInputStream();
|
||||||
|
//创建可设置位置的文件
|
||||||
|
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
|
||||||
|
//设置每条线程写入文件的位置
|
||||||
|
file.seek(mConfig.START_LOCATION);
|
||||||
|
byte[] buffer = new byte[mBufSize];
|
||||||
|
int len;
|
||||||
|
//当前子线程的下载位置
|
||||||
|
mChildCurrentLocation = mConfig.START_LOCATION;
|
||||||
|
while ((len = is.read(buffer)) != -1) {
|
||||||
|
if (STATE.isCancel) break;
|
||||||
|
if (STATE.isStop) break;
|
||||||
|
if (mSleepTime > 0) Thread.sleep(mSleepTime);
|
||||||
|
file.write(buffer, 0, len);
|
||||||
|
progress(len);
|
||||||
|
}
|
||||||
|
if (STATE.isCancel || STATE.isStop) return;
|
||||||
|
//支持断点的处理
|
||||||
|
if (mConfig.IS_SUPPORT_BREAK_POINT) {
|
||||||
|
Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
|
||||||
|
writeConfig(true, 1);
|
||||||
|
STATE.COMPLETE_THREAD_NUM++;
|
||||||
|
if (STATE.isComplete()) {
|
||||||
|
File configFile = new File(mConfigFPath);
|
||||||
|
if (configFile.exists()) {
|
||||||
|
configFile.delete();
|
||||||
|
}
|
||||||
|
STATE.isDownloading = false;
|
||||||
|
mListener.onComplete();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "下载任务完成");
|
||||||
|
STATE.isDownloading = false;
|
||||||
|
mListener.onComplete();
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
failDownload(mChildCurrentLocation, "下载链接异常", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
failDownload(mChildCurrentLocation, "下载失败【" + mConfig.DOWNLOAD_URL + "】", e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
failDownload(mChildCurrentLocation, "获取流失败", e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (file != null) {
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
if (is != null) {
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
if (conn != null) {
|
||||||
|
conn.disconnect();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
|
interface OnFileInfoCallback {
|
||||||
|
/**
|
||||||
|
* 处理完成
|
||||||
|
*
|
||||||
|
* @param code 状态码
|
||||||
|
*/
|
||||||
|
void onComplete(String url, int code);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求失败
|
||||||
|
*
|
||||||
|
* @param errorMsg 错误信息
|
||||||
|
*/
|
||||||
|
void onFail(String url, String errorMsg);
|
||||||
|
}
|
@ -14,17 +14,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.arialyy.aria.core.download.downloader.http;
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadListener;
|
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lyy on 2015/8/25.
|
* Created by lyy on 2015/8/25.
|
||||||
* 简单的下载工具
|
* HTTP单任务下载工具
|
||||||
*/
|
*/
|
||||||
public class SimpleDownloadUtil implements IDownloadUtil, Runnable {
|
public class SimpleDownloadUtil implements IDownloadUtil, Runnable {
|
||||||
private static final String TAG = "SimpleDownloadUtil";
|
private static final String TAG = "SimpleDownloadUtil";
|
||||||
@ -89,8 +87,20 @@ public class SimpleDownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
if (TextUtils.isEmpty(mTaskEntity.redirectUrl)) {
|
if (mTaskEntity.getEntity().getFileSize() <= 1) {
|
||||||
new Thread(new FileInfoThread(mTaskEntity, new FileInfoThread.OnFileInfoCallback() {
|
new Thread(createInfoThread()).start();
|
||||||
|
} else {
|
||||||
|
mDT.startDownload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过链接类型创建不同的获取文件信息的线程
|
||||||
|
*/
|
||||||
|
private Runnable createInfoThread() {
|
||||||
|
switch (mTaskEntity.downloadType) {
|
||||||
|
case AbsTaskEntity.FTP:
|
||||||
|
return new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
|
||||||
@Override public void onComplete(String url, int code) {
|
@Override public void onComplete(String url, int code) {
|
||||||
mDT.startDownload();
|
mDT.startDownload();
|
||||||
}
|
}
|
||||||
@ -98,9 +108,18 @@ public class SimpleDownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
@Override public void onFail(String url, String errorMsg) {
|
@Override public void onFail(String url, String errorMsg) {
|
||||||
failDownload(errorMsg);
|
failDownload(errorMsg);
|
||||||
}
|
}
|
||||||
})).start();
|
});
|
||||||
} else {
|
case AbsTaskEntity.HTTP:
|
||||||
|
return new HttpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
|
||||||
|
@Override public void onComplete(String url, int code) {
|
||||||
mDT.startDownload();
|
mDT.startDownload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public void onFail(String url, String errorMsg) {
|
||||||
|
failDownload(errorMsg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,23 +19,23 @@ package com.arialyy.aria.core.download.downloader;
|
|||||||
* Created by lyy on 2017/1/18.
|
* Created by lyy on 2017/1/18.
|
||||||
* 下载状态常量
|
* 下载状态常量
|
||||||
*/
|
*/
|
||||||
public class StateConstance {
|
class StateConstance {
|
||||||
public int CANCEL_NUM = 0;
|
int CANCEL_NUM = 0;
|
||||||
public int STOP_NUM = 0;
|
int STOP_NUM = 0;
|
||||||
public int FAIL_NUM = 0;
|
int FAIL_NUM = 0;
|
||||||
public int CONNECT_TIME_OUT; //连接超时时间
|
int CONNECT_TIME_OUT; //连接超时时间
|
||||||
public int READ_TIME_OUT; //流读取的超时时间
|
int READ_TIME_OUT; //流读取的超时时间
|
||||||
public int COMPLETE_THREAD_NUM = 0;
|
int COMPLETE_THREAD_NUM = 0;
|
||||||
public int THREAD_NUM;
|
int THREAD_NUM;
|
||||||
public long CURRENT_LOCATION = 0;
|
long CURRENT_LOCATION = 0;
|
||||||
public boolean isDownloading = false;
|
boolean isDownloading = false;
|
||||||
public boolean isCancel = false;
|
boolean isCancel = false;
|
||||||
public boolean isStop = false;
|
boolean isStop = false;
|
||||||
|
|
||||||
public StateConstance() {
|
StateConstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanState() {
|
void cleanState() {
|
||||||
isCancel = false;
|
isCancel = false;
|
||||||
isStop = false;
|
isStop = false;
|
||||||
isDownloading = true;
|
isDownloading = true;
|
||||||
@ -48,28 +48,28 @@ public class StateConstance {
|
|||||||
/**
|
/**
|
||||||
* 所有子线程是否都已经停止下载
|
* 所有子线程是否都已经停止下载
|
||||||
*/
|
*/
|
||||||
public boolean isStop() {
|
boolean isStop() {
|
||||||
return STOP_NUM == THREAD_NUM;
|
return STOP_NUM == THREAD_NUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有子线程是否都已经下载失败
|
* 所有子线程是否都已经下载失败
|
||||||
*/
|
*/
|
||||||
public boolean isFail() {
|
boolean isFail() {
|
||||||
return FAIL_NUM == THREAD_NUM;
|
return FAIL_NUM == THREAD_NUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有子线程是否都已经完成下载
|
* 所有子线程是否都已经完成下载
|
||||||
*/
|
*/
|
||||||
public boolean isComplete() {
|
boolean isComplete() {
|
||||||
return COMPLETE_THREAD_NUM == THREAD_NUM;
|
return COMPLETE_THREAD_NUM == THREAD_NUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有子线程是否都已经取消下载
|
* 所有子线程是否都已经取消下载
|
||||||
*/
|
*/
|
||||||
public boolean isCancel() {
|
boolean isCancel() {
|
||||||
return CANCEL_NUM == THREAD_NUM;
|
return CANCEL_NUM == THREAD_NUM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.arialyy.aria.core.download.downloader;
|
||||||
|
|
||||||
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子线程下载信息类
|
||||||
|
*/
|
||||||
|
class SubThreadConfig {
|
||||||
|
//线程Id
|
||||||
|
int THREAD_ID;
|
||||||
|
//下载文件大小
|
||||||
|
long FILE_SIZE;
|
||||||
|
//子线程启动下载位置
|
||||||
|
long START_LOCATION;
|
||||||
|
//子线程结束下载位置
|
||||||
|
long END_LOCATION;
|
||||||
|
//下载路径
|
||||||
|
File TEMP_FILE;
|
||||||
|
String DOWNLOAD_URL;
|
||||||
|
String CONFIG_FILE_PATH;
|
||||||
|
DownloadTaskEntity DOWNLOAD_TASK_ENTITY;
|
||||||
|
boolean IS_SUPPORT_BREAK_POINT = true;
|
||||||
|
}
|
@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.arialyy.aria.core.download.downloader.ftp;
|
|
||||||
|
|
||||||
import com.arialyy.aria.core.download.DownloadEntity;
|
|
||||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadListener;
|
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
|
|
||||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import org.apache.commons.net.ftp.FTP;
|
|
||||||
import org.apache.commons.net.ftp.FTPClient;
|
|
||||||
import org.apache.commons.net.ftp.FTPFile;
|
|
||||||
import org.apache.commons.net.ftp.FTPFileEntryParser;
|
|
||||||
import org.apache.commons.net.ftp.FTPListParseEngine;
|
|
||||||
import org.apache.commons.net.ftp.FTPReply;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Aria.Lao on 2017/7/21.
|
|
||||||
*/
|
|
||||||
public class FtpDownloadUtil implements IDownloadUtil, Runnable {
|
|
||||||
|
|
||||||
private IDownloadListener mListener;
|
|
||||||
private DownloadTaskEntity mTaskEntity;
|
|
||||||
private DownloadEntity mEntity;
|
|
||||||
|
|
||||||
public FtpDownloadUtil(DownloadTaskEntity entity, IDownloadListener downloadListener) {
|
|
||||||
mTaskEntity = entity;
|
|
||||||
mListener = downloadListener;
|
|
||||||
mEntity = mTaskEntity.getEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public long getFileSize() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public long getCurrentLocation() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean isDownloading() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void cancelDownload() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void stopDownload() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void startDownload() {
|
|
||||||
mListener.onPre();
|
|
||||||
new Thread(this).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void resumeDownload() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void setMaxSpeed(double maxSpeed) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void run() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void failDownload(String msg) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void test() throws IOException {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,281 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.arialyy.aria.core.download.downloader.ftp;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
import com.arialyy.aria.core.AriaManager;
|
|
||||||
import com.arialyy.aria.core.download.DownloadEntity;
|
|
||||||
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
|
||||||
import com.arialyy.aria.core.download.downloader.ChildThreadConfigEntity;
|
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadListener;
|
|
||||||
import com.arialyy.aria.core.download.downloader.StateConstance;
|
|
||||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Properties;
|
|
||||||
import org.apache.commons.net.ftp.FTP;
|
|
||||||
import org.apache.commons.net.ftp.FTPClient;
|
|
||||||
import org.apache.commons.net.ftp.FTPFile;
|
|
||||||
import org.apache.commons.net.ftp.FTPReply;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Aria.Lao on 2017/7/24.
|
|
||||||
* Ftp下载任务
|
|
||||||
*/
|
|
||||||
class FtpThreadTask implements Runnable {
|
|
||||||
private final String TAG = "FtpThreadTask";
|
|
||||||
private ChildThreadConfigEntity mConfig;
|
|
||||||
private String mConfigFPath;
|
|
||||||
private long mChildCurrentLocation = 0;
|
|
||||||
private int mBufSize;
|
|
||||||
private IDownloadListener mListener;
|
|
||||||
private StateConstance STATE;
|
|
||||||
private long mSleepTime = 0;
|
|
||||||
private DownloadTaskEntity mTaskEntity;
|
|
||||||
private DownloadEntity mEntity;
|
|
||||||
|
|
||||||
FtpThreadTask(StateConstance constance, IDownloadListener listener,
|
|
||||||
ChildThreadConfigEntity downloadInfo) {
|
|
||||||
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
|
|
||||||
STATE = constance;
|
|
||||||
STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();
|
|
||||||
STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut();
|
|
||||||
mListener = listener;
|
|
||||||
this.mConfig = downloadInfo;
|
|
||||||
mConfigFPath = downloadInfo.CONFIG_FILE_PATH;
|
|
||||||
mTaskEntity = mConfig.DOWNLOAD_TASK_ENTITY;
|
|
||||||
mEntity = mTaskEntity.getEntity();
|
|
||||||
mBufSize = manager.getDownloadConfig().getBuffSize();
|
|
||||||
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed());
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMaxSpeed(double maxSpeed) {
|
|
||||||
if (-0.9999 < maxSpeed && maxSpeed < 0.00001) {
|
|
||||||
mSleepTime = 0;
|
|
||||||
} else {
|
|
||||||
BigDecimal db = new BigDecimal(
|
|
||||||
((mBufSize / 1024) * (filterVersion() ? 1 : STATE.THREAD_NUM) / maxSpeed) * 1000);
|
|
||||||
mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean filterVersion() {
|
|
||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void run() {
|
|
||||||
FTPClient client = null;
|
|
||||||
InputStream is = null;
|
|
||||||
BufferedRandomAccessFile file = null;
|
|
||||||
try {
|
|
||||||
Log.d(TAG, "任务【"
|
|
||||||
+ mConfig.TEMP_FILE.getName()
|
|
||||||
+ "】线程__"
|
|
||||||
+ mConfig.THREAD_ID
|
|
||||||
+ "__开始下载【开始位置 : "
|
|
||||||
+ mConfig.START_LOCATION
|
|
||||||
+ ",结束位置:"
|
|
||||||
+ mConfig.END_LOCATION
|
|
||||||
+ "】");
|
|
||||||
client = new FTPClient();
|
|
||||||
//ip和端口
|
|
||||||
String[] temp = mEntity.getDownloadUrl().split("/");
|
|
||||||
String[] pp = temp[2].split(":");
|
|
||||||
String dir = temp[temp.length - 2];
|
|
||||||
String fileName = temp[temp.length - 1];
|
|
||||||
client.connect(pp[0], Integer.parseInt(pp[1]));
|
|
||||||
if (!TextUtils.isEmpty(mTaskEntity.account)) {
|
|
||||||
client.login(mTaskEntity.userName, mTaskEntity.userPw);
|
|
||||||
} else {
|
|
||||||
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
|
|
||||||
}
|
|
||||||
int reply = client.getReplyCode();
|
|
||||||
if (!FTPReply.isPositiveCompletion(reply)) {
|
|
||||||
client.disconnect();
|
|
||||||
failDownload(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
client.enterLocalPassiveMode();
|
|
||||||
client.setFileType(FTP.BINARY_FILE_TYPE);
|
|
||||||
FTPFile[] files = client.listFiles(fileName);
|
|
||||||
files[0].getSize();
|
|
||||||
client.setRestartOffset(mConfig.START_LOCATION);
|
|
||||||
is = client.retrieveFileStream(fileName);
|
|
||||||
//创建可设置位置的文件
|
|
||||||
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
|
|
||||||
//设置每条线程写入文件的位置
|
|
||||||
file.seek(mConfig.START_LOCATION);
|
|
||||||
byte[] buffer = new byte[mBufSize];
|
|
||||||
int len;
|
|
||||||
//当前子线程的下载位置
|
|
||||||
mChildCurrentLocation = mConfig.START_LOCATION;
|
|
||||||
while ((len = is.read(buffer)) != -1) {
|
|
||||||
if (STATE.isCancel) break;
|
|
||||||
if (STATE.isStop) break;
|
|
||||||
if (mSleepTime > 0) Thread.sleep(mSleepTime);
|
|
||||||
file.write(buffer, 0, len);
|
|
||||||
progress(len);
|
|
||||||
}
|
|
||||||
if (STATE.isCancel) return;
|
|
||||||
//停止状态不需要删除记录文件
|
|
||||||
if (STATE.isStop) return;
|
|
||||||
//支持断点的处理
|
|
||||||
if (mConfig.IS_SUPPORT_BREAK_POINT) {
|
|
||||||
Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__下载完毕");
|
|
||||||
writeConfig(true, 1);
|
|
||||||
STATE.COMPLETE_THREAD_NUM++;
|
|
||||||
if (STATE.isComplete()) {
|
|
||||||
File configFile = new File(mConfigFPath);
|
|
||||||
if (configFile.exists()) {
|
|
||||||
configFile.delete();
|
|
||||||
}
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onComplete();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "下载任务完成");
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onComplete();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
failDownload(mChildCurrentLocation, "下载失败【" + mConfig.DOWNLOAD_URL + "】", e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
failDownload(mChildCurrentLocation, "获取流失败", e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (file != null) {
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
if (is != null) {
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
if (client != null) {
|
|
||||||
client.logout();
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止下载
|
|
||||||
*/
|
|
||||||
protected void stop() {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
try {
|
|
||||||
STATE.STOP_NUM++;
|
|
||||||
Log.d(TAG, "任务【"
|
|
||||||
+ mConfig.TEMP_FILE.getName()
|
|
||||||
+ "】thread__"
|
|
||||||
+ mConfig.THREAD_ID
|
|
||||||
+ "__停止, stop location ==> "
|
|
||||||
+ mChildCurrentLocation);
|
|
||||||
writeConfig(false, mChildCurrentLocation);
|
|
||||||
if (STATE.isStop()) {
|
|
||||||
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onStop(STATE.CURRENT_LOCATION);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载中
|
|
||||||
*/
|
|
||||||
private void progress(long len) {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
mChildCurrentLocation += len;
|
|
||||||
STATE.CURRENT_LOCATION += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消下载
|
|
||||||
*/
|
|
||||||
protected void cancel() {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
STATE.CANCEL_NUM++;
|
|
||||||
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__取消下载");
|
|
||||||
if (STATE.isCancel()) {
|
|
||||||
File configFile = new File(mConfigFPath);
|
|
||||||
if (configFile.exists()) {
|
|
||||||
configFile.delete();
|
|
||||||
}
|
|
||||||
if (mConfig.TEMP_FILE.exists()) {
|
|
||||||
mConfig.TEMP_FILE.delete();
|
|
||||||
}
|
|
||||||
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已取消");
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onCancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载失败
|
|
||||||
*/
|
|
||||||
private void failDownload(long currentLocation, String msg, Exception ex) {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
try {
|
|
||||||
STATE.FAIL_NUM++;
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
STATE.isStop = true;
|
|
||||||
if (ex != null) {
|
|
||||||
Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
|
|
||||||
}
|
|
||||||
writeConfig(false, currentLocation);
|
|
||||||
if (STATE.isFail()) {
|
|
||||||
Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】下载失败");
|
|
||||||
mListener.onFail();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将记录写入到配置文件
|
|
||||||
*/
|
|
||||||
private void writeConfig(boolean isComplete, long record) throws IOException {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
String key = null, value = null;
|
|
||||||
if (0 < record && record < mConfig.END_LOCATION) {
|
|
||||||
key = mConfig.TEMP_FILE.getName() + "_record_" + mConfig.THREAD_ID;
|
|
||||||
value = String.valueOf(record);
|
|
||||||
} else if (record >= mConfig.END_LOCATION || isComplete) {
|
|
||||||
key = mConfig.TEMP_FILE.getName() + "_state_" + mConfig.THREAD_ID;
|
|
||||||
value = "1";
|
|
||||||
}
|
|
||||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
|
||||||
File configFile = new File(mConfigFPath);
|
|
||||||
Properties pro = CommonUtil.loadConfig(configFile);
|
|
||||||
pro.setProperty(key, value);
|
|
||||||
CommonUtil.saveConfig(configFile, pro);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,291 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.arialyy.aria.core.download.downloader.http;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
import com.arialyy.aria.core.AriaManager;
|
|
||||||
import com.arialyy.aria.core.download.downloader.ChildThreadConfigEntity;
|
|
||||||
import com.arialyy.aria.core.download.downloader.IDownloadListener;
|
|
||||||
import com.arialyy.aria.core.download.downloader.StateConstance;
|
|
||||||
import com.arialyy.aria.util.BufferedRandomAccessFile;
|
|
||||||
import com.arialyy.aria.util.CommonUtil;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by lyy on 2017/1/18.
|
|
||||||
* 下载线程
|
|
||||||
*/
|
|
||||||
final class HttpThreadTask implements Runnable {
|
|
||||||
private static final String TAG = "HttpThreadTask";
|
|
||||||
private ChildThreadConfigEntity mConfigEntity;
|
|
||||||
private String mConfigFPath;
|
|
||||||
private long mChildCurrentLocation = 0;
|
|
||||||
private int mBufSize;
|
|
||||||
private IDownloadListener mListener;
|
|
||||||
private StateConstance STATE;
|
|
||||||
private long mSleepTime = 0;
|
|
||||||
|
|
||||||
HttpThreadTask(StateConstance constance, IDownloadListener listener,
|
|
||||||
ChildThreadConfigEntity downloadInfo) {
|
|
||||||
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
|
|
||||||
STATE = constance;
|
|
||||||
STATE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();
|
|
||||||
STATE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut();
|
|
||||||
mListener = listener;
|
|
||||||
this.mConfigEntity = downloadInfo;
|
|
||||||
if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
|
|
||||||
mConfigFPath = downloadInfo.CONFIG_FILE_PATH;
|
|
||||||
}
|
|
||||||
mBufSize = manager.getDownloadConfig().getBuffSize();
|
|
||||||
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed());
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMaxSpeed(double maxSpeed) {
|
|
||||||
if (-0.9999 < maxSpeed && maxSpeed < 0.00001) {
|
|
||||||
mSleepTime = 0;
|
|
||||||
} else {
|
|
||||||
BigDecimal db = new BigDecimal(
|
|
||||||
((mBufSize / 1024) * (filterVersion() ? 1 : STATE.THREAD_NUM) / maxSpeed) * 1000);
|
|
||||||
mSleepTime = db.setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean filterVersion() {
|
|
||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void run() {
|
|
||||||
HttpURLConnection conn = null;
|
|
||||||
InputStream is = null;
|
|
||||||
BufferedRandomAccessFile file = null;
|
|
||||||
try {
|
|
||||||
URL url = new URL(mConfigEntity.DOWNLOAD_URL);
|
|
||||||
conn = ConnectionHelp.handleConnection(url);
|
|
||||||
if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
|
|
||||||
Log.d(TAG, "任务【"
|
|
||||||
+ mConfigEntity.TEMP_FILE.getName()
|
|
||||||
+ "】线程__"
|
|
||||||
+ mConfigEntity.THREAD_ID
|
|
||||||
+ "__开始下载【开始位置 : "
|
|
||||||
+ mConfigEntity.START_LOCATION
|
|
||||||
+ ",结束位置:"
|
|
||||||
+ mConfigEntity.END_LOCATION
|
|
||||||
+ "】");
|
|
||||||
//在头里面请求下载开始位置和结束位置
|
|
||||||
conn.setRequestProperty("Range",
|
|
||||||
"bytes=" + mConfigEntity.START_LOCATION + "-" + (mConfigEntity.END_LOCATION - 1));
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "该下载不支持断点");
|
|
||||||
}
|
|
||||||
conn = ConnectionHelp.setConnectParam(mConfigEntity.DOWNLOAD_TASK_ENTITY, conn);
|
|
||||||
conn.setConnectTimeout(STATE.CONNECT_TIME_OUT);
|
|
||||||
conn.setReadTimeout(STATE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数
|
|
||||||
is = conn.getInputStream();
|
|
||||||
//创建可设置位置的文件
|
|
||||||
file = new BufferedRandomAccessFile(mConfigEntity.TEMP_FILE, "rwd", mBufSize);
|
|
||||||
//设置每条线程写入文件的位置
|
|
||||||
file.seek(mConfigEntity.START_LOCATION);
|
|
||||||
byte[] buffer = new byte[mBufSize];
|
|
||||||
int len;
|
|
||||||
//当前子线程的下载位置
|
|
||||||
mChildCurrentLocation = mConfigEntity.START_LOCATION;
|
|
||||||
while ((len = is.read(buffer)) != -1) {
|
|
||||||
if (STATE.isCancel) break;
|
|
||||||
if (STATE.isStop) break;
|
|
||||||
if (mSleepTime > 0) Thread.sleep(mSleepTime);
|
|
||||||
file.write(buffer, 0, len);
|
|
||||||
progress(len);
|
|
||||||
}
|
|
||||||
if (STATE.isCancel) return;
|
|
||||||
//停止状态不需要删除记录文件
|
|
||||||
if (STATE.isStop) return;
|
|
||||||
//支持断点的处理
|
|
||||||
if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
|
|
||||||
Log.i(TAG, "任务【"
|
|
||||||
+ mConfigEntity.TEMP_FILE.getName()
|
|
||||||
+ "】线程__"
|
|
||||||
+ mConfigEntity.THREAD_ID
|
|
||||||
+ "__下载完毕");
|
|
||||||
writeConfig(true, 1);
|
|
||||||
STATE.COMPLETE_THREAD_NUM++;
|
|
||||||
if (STATE.isComplete()) {
|
|
||||||
File configFile = new File(mConfigFPath);
|
|
||||||
if (configFile.exists()) {
|
|
||||||
configFile.delete();
|
|
||||||
}
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onComplete();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "下载任务完成");
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onComplete();
|
|
||||||
}
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
failDownload(mChildCurrentLocation, "下载链接异常", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
failDownload(mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
failDownload(mChildCurrentLocation, "获取流失败", e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (file != null) {
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
if (is != null) {
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
if (conn != null) {
|
|
||||||
conn.disconnect();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止下载
|
|
||||||
*/
|
|
||||||
protected void stop() {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
try {
|
|
||||||
if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
|
|
||||||
STATE.STOP_NUM++;
|
|
||||||
Log.d(TAG, "任务【"
|
|
||||||
+ mConfigEntity.TEMP_FILE.getName()
|
|
||||||
+ "】thread__"
|
|
||||||
+ mConfigEntity.THREAD_ID
|
|
||||||
+ "__停止, stop location ==> "
|
|
||||||
+ mChildCurrentLocation);
|
|
||||||
writeConfig(false, mChildCurrentLocation);
|
|
||||||
if (STATE.isStop()) {
|
|
||||||
Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已停止");
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onStop(STATE.CURRENT_LOCATION);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已停止");
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onStop(STATE.CURRENT_LOCATION);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载中
|
|
||||||
*/
|
|
||||||
private void progress(long len) {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
mChildCurrentLocation += len;
|
|
||||||
STATE.CURRENT_LOCATION += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 取消下载
|
|
||||||
*/
|
|
||||||
protected void cancel() {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
|
|
||||||
STATE.CANCEL_NUM++;
|
|
||||||
Log.d(TAG, "任务【"
|
|
||||||
+ mConfigEntity.TEMP_FILE.getName()
|
|
||||||
+ "】thread__"
|
|
||||||
+ mConfigEntity.THREAD_ID
|
|
||||||
+ "__取消下载");
|
|
||||||
if (STATE.isCancel()) {
|
|
||||||
File configFile = new File(mConfigFPath);
|
|
||||||
if (configFile.exists()) {
|
|
||||||
configFile.delete();
|
|
||||||
}
|
|
||||||
if (mConfigEntity.TEMP_FILE.exists()) {
|
|
||||||
mConfigEntity.TEMP_FILE.delete();
|
|
||||||
}
|
|
||||||
Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已取消");
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onCancel();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】已取消");
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
mListener.onCancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载失败
|
|
||||||
*/
|
|
||||||
private void failDownload(long currentLocation, String msg, Exception ex) {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
try {
|
|
||||||
STATE.FAIL_NUM++;
|
|
||||||
STATE.isDownloading = false;
|
|
||||||
STATE.isStop = true;
|
|
||||||
if (ex != null) {
|
|
||||||
Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
|
|
||||||
}
|
|
||||||
if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
|
|
||||||
writeConfig(false, currentLocation);
|
|
||||||
if (STATE.isFail()) {
|
|
||||||
Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败");
|
|
||||||
mListener.onFail();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败");
|
|
||||||
mListener.onFail();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将记录写入到配置文件
|
|
||||||
*/
|
|
||||||
private void writeConfig(boolean isComplete, long record) throws IOException {
|
|
||||||
synchronized (AriaManager.LOCK) {
|
|
||||||
String key = null, value = null;
|
|
||||||
if (0 < record && record < mConfigEntity.END_LOCATION) {
|
|
||||||
key = mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID;
|
|
||||||
value = String.valueOf(record);
|
|
||||||
} else if (record >= mConfigEntity.END_LOCATION || isComplete) {
|
|
||||||
key = mConfigEntity.TEMP_FILE.getName() + "_state_" + mConfigEntity.THREAD_ID;
|
|
||||||
value = "1";
|
|
||||||
}
|
|
||||||
if (!TextUtils.isEmpty(key) && !TextUtils.isEmpty(value)) {
|
|
||||||
File configFile = new File(mConfigFPath);
|
|
||||||
Properties pro = CommonUtil.loadConfig(configFile);
|
|
||||||
pro.setProperty(key, value);
|
|
||||||
CommonUtil.saveConfig(configFile, pro);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -39,6 +39,11 @@ public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
|
|||||||
*/
|
*/
|
||||||
public Map<String, String> headers = new HashMap<>();
|
public Map<String, String> headers = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符编码,默认为"utf-8"
|
||||||
|
*/
|
||||||
|
public String charSet = "utf-8";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网络请求类型
|
* 网络请求类型
|
||||||
*/
|
*/
|
||||||
|
@ -102,7 +102,7 @@ final class UploadUtil implements Runnable {
|
|||||||
mListener.onPostPre(uploadFile.length());
|
mListener.onPostPre(uploadFile.length());
|
||||||
|
|
||||||
PrintWriter writer =
|
PrintWriter writer =
|
||||||
new PrintWriter(new OutputStreamWriter(mOutputStream, mTaskEntity.charset), true);
|
new PrintWriter(new OutputStreamWriter(mOutputStream, mTaskEntity.charSet), true);
|
||||||
|
|
||||||
//添加文件上传表单字段
|
//添加文件上传表单字段
|
||||||
keys = mTaskEntity.formFields.keySet();
|
keys = mTaskEntity.formFields.keySet();
|
||||||
@ -143,7 +143,7 @@ final class UploadUtil implements Runnable {
|
|||||||
.append("\"")
|
.append("\"")
|
||||||
.append(LINE_END);
|
.append(LINE_END);
|
||||||
writer.append("Content-Type: text/plain; charset=")
|
writer.append("Content-Type: text/plain; charset=")
|
||||||
.append(mTaskEntity.charset)
|
.append(mTaskEntity.charSet)
|
||||||
.append(LINE_END);
|
.append(LINE_END);
|
||||||
writer.append(LINE_END);
|
writer.append(LINE_END);
|
||||||
writer.append(value).append(LINE_END);
|
writer.append(value).append(LINE_END);
|
||||||
|
@ -37,6 +37,7 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@ -63,6 +64,18 @@ import java.lang.reflect.WildcardType;
|
|||||||
public class CommonUtil {
|
public class CommonUtil {
|
||||||
private static final String TAG = "CommonUtil";
|
private static final String TAG = "CommonUtil";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串编码转换
|
||||||
|
*/
|
||||||
|
public static String strCharSetConvert(String oldStr, String charSet) {
|
||||||
|
try {
|
||||||
|
return new String(oldStr.getBytes(), charSet);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实例化泛型的实际类型参数
|
* 实例化泛型的实际类型参数
|
||||||
*
|
*
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
<activity android:name=".download.HighestPriorityActivity"/>
|
<activity android:name=".download.HighestPriorityActivity"/>
|
||||||
<activity android:name=".test.TestMutilTaskSysDownload"/>
|
<activity android:name=".test.TestMutilTaskSysDownload"/>
|
||||||
<activity android:name=".download.group.DownloadGroupActivity"/>
|
<activity android:name=".download.group.DownloadGroupActivity"/>
|
||||||
|
<activity android:name=".download.FtpDownloadActivity"/>
|
||||||
|
|
||||||
<service android:name=".download.service_download.DownloadService"/>
|
<service android:name=".download.service_download.DownloadService"/>
|
||||||
</application>
|
</application>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<download>
|
<download>
|
||||||
|
|
||||||
<!--设置下载线程,线程下载数改变后,新的下载任务才会生效,如果任务大小小于1m,该设置也不会生效-->
|
<!--设置下载线程,线程下载数改变后,新的下载任务才会生效,如果任务大小小于1m,该设置也不会生效-->
|
||||||
<threadNum value="4"/>
|
<threadNum value="3"/>
|
||||||
|
|
||||||
<!--设置下载队列最大任务数, 默认为2-->
|
<!--设置下载队列最大任务数, 默认为2-->
|
||||||
<maxTaskNum value="4"/>
|
<maxTaskNum value="4"/>
|
||||||
|
@ -23,6 +23,7 @@ import butterknife.OnClick;
|
|||||||
import com.arialyy.simple.base.BaseActivity;
|
import com.arialyy.simple.base.BaseActivity;
|
||||||
import com.arialyy.simple.databinding.ActivityMainBinding;
|
import com.arialyy.simple.databinding.ActivityMainBinding;
|
||||||
import com.arialyy.simple.download.DownloadActivity;
|
import com.arialyy.simple.download.DownloadActivity;
|
||||||
|
import com.arialyy.simple.download.FtpDownloadActivity;
|
||||||
import com.arialyy.simple.download.group.DownloadGroupActivity;
|
import com.arialyy.simple.download.group.DownloadGroupActivity;
|
||||||
import com.arialyy.simple.test.TestMutilTaskSysDownload;
|
import com.arialyy.simple.test.TestMutilTaskSysDownload;
|
||||||
import com.arialyy.simple.upload.UploadActivity;
|
import com.arialyy.simple.upload.UploadActivity;
|
||||||
@ -44,7 +45,7 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@OnClick({R.id.download, R.id.upload, R.id.download_task_group})
|
@OnClick({R.id.download, R.id.upload, R.id.download_task_group, R.id.ftp})
|
||||||
public void funcation(View view){
|
public void funcation(View view){
|
||||||
switch (view.getId()){
|
switch (view.getId()){
|
||||||
case R.id.download:
|
case R.id.download:
|
||||||
@ -56,6 +57,9 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
|
|||||||
case R.id.download_task_group:
|
case R.id.download_task_group:
|
||||||
startActivity(new Intent(this, DownloadGroupActivity.class));
|
startActivity(new Intent(this, DownloadGroupActivity.class));
|
||||||
break;
|
break;
|
||||||
|
case R.id.ftp:
|
||||||
|
startActivity(new Intent(this, FtpDownloadActivity.class));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.simple.download;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import com.arialyy.annotations.Download;
|
||||||
|
import com.arialyy.aria.core.Aria;
|
||||||
|
import com.arialyy.aria.core.download.DownloadTask;
|
||||||
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import com.arialyy.frame.util.show.T;
|
||||||
|
import com.arialyy.simple.R;
|
||||||
|
import com.arialyy.simple.base.BaseActivity;
|
||||||
|
import com.arialyy.simple.databinding.ActivityFtpDownloadBinding;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/7/25.
|
||||||
|
* Ftp下载测试
|
||||||
|
*/
|
||||||
|
public class FtpDownloadActivity extends BaseActivity<ActivityFtpDownloadBinding> {
|
||||||
|
|
||||||
|
@Override protected void init(Bundle savedInstanceState) {
|
||||||
|
super.init(savedInstanceState);
|
||||||
|
Aria.download(this).register();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClick(View view) {
|
||||||
|
switch (view.getId()) {
|
||||||
|
case R.id.start:
|
||||||
|
Aria.download(this)
|
||||||
|
//.load("172.18.104.129", "21", "cd.mp3")
|
||||||
|
.load("172.18.104.129", "21", "gg.png")
|
||||||
|
.login("lao", "123456")
|
||||||
|
.setDownloadPath("/mnt/sdcard/tt.png")
|
||||||
|
.charSet("gbk")
|
||||||
|
.start();
|
||||||
|
break;
|
||||||
|
case R.id.stop:
|
||||||
|
break;
|
||||||
|
case R.id.cancel:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onPre() protected void onPre(DownloadTask task) {
|
||||||
|
L.d(TAG, "ftp pre");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onTaskPre() protected void onTaskPre(DownloadTask task) {
|
||||||
|
L.d(TAG, "ftp task pre");
|
||||||
|
getBinding().setFileSize(task.getConvertFileSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onTaskStart() void taskStart(DownloadTask task) {
|
||||||
|
L.d(TAG, "ftp task start");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onTaskRunning() protected void running(DownloadTask task) {
|
||||||
|
getBinding().setProgress(task.getPercent());
|
||||||
|
getBinding().setSpeed(task.getConvertSpeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onTaskResume() void taskResume(DownloadTask task) {
|
||||||
|
L.d(TAG, "ftp task resume");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onTaskStop() void taskStop(DownloadTask task) {
|
||||||
|
L.d(TAG, "ftp task stop");
|
||||||
|
getBinding().setSpeed("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onTaskCancel() void taskCancel(DownloadTask task) {
|
||||||
|
getBinding().setSpeed("");
|
||||||
|
getBinding().setProgress(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onTaskFail() void taskFail(DownloadTask task) {
|
||||||
|
L.d(TAG, "ftp task fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Download.onTaskComplete() void taskComplete(DownloadTask task) {
|
||||||
|
getBinding().setProgress(100);
|
||||||
|
Log.d(TAG, "md5 ==> " + CommonUtil.getFileMD5(new File(task.getDownloadPath())));
|
||||||
|
T.showShort(this, "FTP下载完成");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected int setLayoutId() {
|
||||||
|
return R.layout.activity_ftp_download;
|
||||||
|
}
|
||||||
|
}
|
@ -38,9 +38,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBinding> {
|
public class DownloadGroupActivity extends BaseActivity<ActivityDownloadGroupBinding> {
|
||||||
|
|
||||||
@Bind(R.id.start) Button mStart;
|
|
||||||
@Bind(R.id.stop) Button mStop;
|
|
||||||
@Bind(R.id.cancel) Button mCancel;
|
|
||||||
@Bind(R.id.child_list) SubStateLinearLayout mChildList;
|
@Bind(R.id.child_list) SubStateLinearLayout mChildList;
|
||||||
List<String> mUrls;
|
List<String> mUrls;
|
||||||
|
|
||||||
|
36
app/src/main/res/layout/activity_ftp_download.xml
Normal file
36
app/src/main/res/layout/activity_ftp_download.xml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:bind="http://schemas.android.com/apk/res-auto"
|
||||||
|
>
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="fileSize"
|
||||||
|
type="String"
|
||||||
|
/>
|
||||||
|
<variable
|
||||||
|
name="speed"
|
||||||
|
type="String"
|
||||||
|
/>
|
||||||
|
<variable
|
||||||
|
name="progress"
|
||||||
|
type="int"
|
||||||
|
/>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
|
||||||
|
<include layout="@layout/layout_bar"/>
|
||||||
|
|
||||||
|
<include
|
||||||
|
layout="@layout/content_single"
|
||||||
|
bind:fileSize="@{fileSize}"
|
||||||
|
bind:progress="@{progress}"
|
||||||
|
bind:speed="@{speed}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
@ -33,5 +33,13 @@
|
|||||||
style="?buttonBarButtonStyle"
|
style="?buttonBarButtonStyle"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/ftp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="FTP 下载"
|
||||||
|
style="?buttonBarButtonStyle"
|
||||||
|
/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -30,7 +30,6 @@ public class UploadTaskEntity extends AbsTaskEntity<UploadEntity> {
|
|||||||
public String attachment; //文件上传需要的key
|
public String attachment; //文件上传需要的key
|
||||||
public String contentType = "multipart/form-data"; //上传的文件类型
|
public String contentType = "multipart/form-data"; //上传的文件类型
|
||||||
public String userAgent = "User-Agent";
|
public String userAgent = "User-Agent";
|
||||||
public String charset = "utf-8";
|
|
||||||
@OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity;
|
@OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user