您的位置:首页 > 理论基础 > 计算机网络

移动架构33_网络访问框架与数据库框架实现断点下载

2017-11-12 11:19 525 查看
Demo地址:https://gitee.com/YuBaoZi/AndroidWenJianDuanDianXiaZai/blob/master/Download.rar

断点下载;

下载任务有优先级;

下载有回调;

网络自封装(fastjson和HttpClient)

数据库存储下载信息;

拓展性好,可以针对不同用户;

要点

掌握网络框架的搭建

掌握数据库框架的封装

掌握数据的下载

网络框架和数据库框架的联合封装使用

数据库作用:记录文件下载记录、文件总长度、文件是否已经下载,可以不用实时更改当前文件的下载进度,利用File的长度,作为下载文件的起始值

一、实现数据库底层框架

具体详解:移动架构29_面向对象式手写数据库架构设计一

1、定义注解

实现业务类属性与数据库表中列名的兼容(翻译以及防止出现关键字)

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DbTable {
String value();
}


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DbFiled {
String value();
}


2、定义操作数据的接口和抽象类

封装表创建、增删改查的行为;业务生成sql语句、查询结果生成业务结果的逻辑是一致的,将其封装。

public interface IBaseDao<T> {
/**
* 插入数据
* @param entity
* @return
*/
Long insert(T entity);

/**
*
* @param entity
* @param where
* @return
*/
int  update(T entity, T where);

/**
* 删除数据
* @param where
* @return
*/
int  delete(T where);

/**
* 查询数据
*/
List<T> query(T where);

List<T> query(T where, String orderBy, Integer startIndex, Integer limit);

List<T> query(String sql);
}


public abstract class BaseDao<T> implements IBaseDao<T> {
private boolean isInit = false;
protected SQLiteDatabase sqLiteDatabase;
private Class<T> entityClass;
private String tableName;
private Map<String, Field> cacheMap;

public String getTableName() {
return tableName;
}

@Override
public Long insert(T entity) {
ContentValues contentValues = getContentValues(entity);
long result = sqLiteDatabase.insert(tableName, null, contentValues);
return result;
}

private ContentValues getContentValues(T entity) {
ContentValues contentValues = new ContentValues();
try {
for (Map.Entry<String,Field> me:cacheMap.entrySet()){
if(me.getValue().get(entity)==null){
continue;
}
contentValues.put(me.getKey(),me.getValue().get(entity).toString());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return contentValues;
}

@Override
public int update(T entity, T where) {
ContentValues contentValues = getContentValues(entity);
Condition condition = new Condition(getContentValues(where));
int update = sqLiteDatabase.update(tableName, contentValues, condition.whereClause, condition.whereArgs);
return update;
}

@Override
public int delete(T where) {
Condition condition = new Condition(getContentValues(where));
int delete = sqLiteDatabase.delete(tableName, condition.whereClause, condition.whereArgs);
return delete;
}

@Override
public List<T> query(T where) {
return query(where,null,null,null);
}

@Override
public List<T> query(T where, String orderBy, Integer startIndex, Integer limit) {
String limitString = null;
if(startIndex!=null && limit!=null){
limitString = startIndex+","+limit;
}
Condition condition = new Condition(getContentValues(where));
Cursor cursor = null;
List<T> result =new ArrayList<>();
try
{
cursor = sqLiteDatabase.query(tableName, null,condition.getWhereClause(),condition.whereArgs,null,null,orderBy,limitString);
result=getResult(cursor,where);
}catch (Exception e){
e.printStackTrace();
}finally {
if(cursor!=null){
cursor.close();
}
}
return result;
}

protected List<T> getResult(Cursor cursor, T where) {
ArrayList list = new ArrayList();
Object item;
while(cursor.moveToNext()){
try {
item = where.getClass().newInstance();
Iterator<Map.Entry<String, Field>> iterator = cacheMap.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String, Field> entry = iterator.next();
String colmunName = entry.getKey();
Field field = entry.getValue();
int columnIndex = cursor.getColumnIndex(colmunName);
Class type = field.getType();
if(columnIndex!=-1){
if(type==String.class){
field.set(item,cursor.getString(columnIndex));
}else if(type==Double.class){
field.set(item,cursor.getDouble(columnIndex));
}else if(type== Integer.class){
field.set(item,cursor.getInt(columnIndex));
}else if(type == Long.class){
field.set(item,cursor.getLong(columnIndex));
}else if(type == byte[].class){
field.set(item,cursor.getBlob(columnIndex));
}else{
/**
* 不支持的类型
*/
continue;
}
}
}
list.add(item);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return list;
}

protected synchronized boolean init(Class<T> entity, SQLiteDatabase sqLiteDatabase) {
if (!isInit) {
this.sqLiteDatabase = sqLiteDatabase;
this.entityClass = entity;
if (entity.getAnnotation(DbTable.class) == null) {
tableName = entity.getClass().getSimpleName();
} else {
tableName = entity.getAnnotation(DbTable.class).value();
}
if (!sqLiteDatabase.isOpen()) {
return false;
}

if (!TextUtils.isEmpty(createTable())) {
sqLiteDatabase.execSQL(createTable());
}
cacheMap = new HashMap<>();
initCatchMap();
isInit = true;
}
return isInit;
}

/**
* 维护映射关系
*/
private void initCatchMap() {
String sql = "select * from " + this.tableName + " limit 1,0";
Cursor cursor = null;
try {
cursor = sqLiteDatabase.rawQuery(sql, null);
/**
* 表的列名数组
*/
String[] columnNames = cursor.getColumnNames();
/**
* 拿到Filed数组
*/
Field[] columnFields = entityClass.getFields();
for (Field filed : columnFields) {
filed.setAccessible(true);

Field columnFiled = null;
String colmunName = null;
/**
* 开始找对应关系
*/
for (String cn : columnNames) {
String filedName = null;
if(filed.getAnnotation(DbFiled.class)!=null){
filedName = filed.getAnnotation(DbFiled.class).value();
}else {
filedName = filed.getName();
}
if(cn.equals(filedName)){
columnFiled = filed;
colmunName = cn;
break;
}
}
//找到了对应关系
if(columnFiled!=null){
cacheMap.put(colmunName,columnFiled);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
cursor.close();
}
}

public abstract String createTable();

class Condition{
/**
* 查询条件
* name=? && password =?
*/
private String whereClause;

private  String[] whereArgs;
public Condition(ContentValues whereClause) {
ArrayList list=new ArrayList();
StringBuilder stringBuilder=new StringBuilder();

stringBuilder.append(" 1=1 ");

Set keys=whereClause.keySet();
Iterator iterator=keys.iterator();
while (iterator.hasNext())
{
String key= (String) iterator.next();
String value= (String) whereClause.get(key);

if (value!=null)
{
/*
拼接条件查询语句
1=1 and name =? and password=?
*/
stringBuilder.append(" and "+key+" =?");
/**
* ?----》value
*/
list.add(value);
}
}
this.whereClause=stringBuilder.toString();
this.whereArgs= (String[]) list.toArray(new String[list.size()]);

}

public String[] getWhereArgs() {
return whereArgs;
}

public String getWhereClause() {
return whereClause;
}
}
}


3、定义提供操作数据库类的工厂类

校验数据库创建、根据类型提供操作表的操作类

public class BaseDaoFactory {

private String sqlitDatabasePath;

private SQLiteDatabase sqLiteDatabase;

private static BaseDaoFactory instance = new BaseDaoFactory();

private BaseDaoFactory() {
sqlitDatabasePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/teacher.db";
openDatabase();
}

public synchronized <T extends BaseDao<M>, M> T getDataHelper(Class<T> clazz, Class<M> entityClass) {
T baseDao = null;
try {
baseDao = clazz.newInstance();
baseDao.init(entityClass, sqLiteDatabase);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return baseDao;
}

private void openDatabase() {
sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqlitDatabasePath, null);

}

public static BaseDaoFactory getInstance() {
return instance;
}

}


二、定义网络框架

具体详解:移动架构32_自定义网络访问框架开发

1、定义网络请求的接口

public interface IHttpListener {
/**
* 网络访问
* 处理结果  回调
* @param httpEntity
*/
void onSuccess(HttpEntity httpEntity);

void onFail();

void addHttpHeader(Map<String,String> headerMap);
}


public interface IHttpService {
/**
* 设置url
* @param url
*/
void setUrl(String url);

/**
* 执行获取网络
*/
void excute();

/**
* 设置处理接口
* @param httpListener
*/
void setHttpListener(IHttpListener httpListener);

/**
* 设置请求参数
* String  1
* byte[]  2
*
*/
void setRequestData(byte[] requestData);

void pause();

/**
*
* 以下的方法是 额外添加的
* 获取请求头的map
* @return
*/
Map<String,String> getHttpHeadMap();

boolean cancle();

boolean isCancle();

boolean isPause();

}


2、请求与回调封装到一个类中

public class RequestHodler<T> {
/**
* 执行下载类
*/
private IHttpService httpService;
/**
* 获取数据  回调结果的类
*/
private IHttpListener httpListener;
/**
* 请求参数对应的实体
*/
private T requestInfo;

private String url;

public IHttpService getHttpService() {
return httpService;
}

public void setHttpService(IHttpService httpService) {
this.httpService = httpService;
}

public IHttpListener getHttpListener() {
return httpListener;
}

public void setHttpListener(IHttpListener httpListener) {
this.httpListener = httpListener;
}

public T getRequestInfo() {
return requestInfo;
}

public void setRequestInfo(T requestInfo) {
this.requestInfo = requestInfo;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}
}


3、定义管理网络请求的线程池

public class ThreadPoolManager {
private static final String TAG ="ThreadPoolManager" ;
private static  ThreadPoolManager instance=new ThreadPoolManager();

private LinkedBlockingQueue<Future<?>> taskQuene=new LinkedBlockingQueue<>();

private ThreadPoolExecutor threadPoolExecutor;
public static ThreadPoolManager getInstance() {
return instance;
}
private ThreadPoolManager()
{
threadPoolExecutor=new ThreadPoolExecutor(4,10,10, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(4), handler);
threadPoolExecutor.execute(runable);
}

public <T> boolean removeTask(FutureTask futureTask)
{
boolean result=false;
/**
* 阻塞式队列是否含有线程
*/
if(taskQuene.contains(futureTask))
{
taskQuene.remove(futureTask);
}else
{
result=threadPoolExecutor.remove(futureTask);
}
return  result;
}

private Runnable runable =new Runnable() {
@Override
public void run() {
while (true)
{
FutureTask futrueTask=null;

try {
/**
* 阻塞式函数
*/
Log.i(TAG,"等待队列     "+taskQuene.size());
futrueTask= (FutureTask) taskQuene.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(futrueTask!=null)
{
threadPoolExecutor.execute(futrueTask);
}
Log.i(TAG,"线程池大小      "+threadPoolExecutor.getPoolSize());
}
}
};
public <T> void execte(FutureTask<T> futureTask) throws InterruptedException {
taskQuene.put(futureTask);
}

private RejectedExecutionHandler handler=new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
taskQuene.put(new FutureTask<Object>(r,null) {
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}


4、定义异步操作作为网络请求实现的平台

public class HttpTask<T> implements Runnable {
private IHttpService httpService;
private FutureTask futureTask;
public HttpTask(RequestHodler<T> requestHodler)
{
httpService=requestHodler.getHttpService();
httpService.setHttpListener(requestHodler.getHttpListener());
httpService.setUrl(requestHodler.getUrl());
//增加方法
IHttpListener httpListener=requestHodler.getHttpListener();
httpListener.addHttpHeader(httpService.getHttpHeadMap());
try {
T request=requestHodler.getRequestInfo();
if(request!=null)
{
String requestInfo= JSON.toJSONString(request);
httpService.setRequestData(requestInfo.getBytes("UTF-8"));
}

} catch (Exception e) {
e.printStackTrace();
}

}

@Override
public void run() {
httpService.excute();
}
/**
* 新增方法
*/
public void start()
{
futureTask=new FutureTask(this,null);
try {
ThreadPoolManager.getInstance().execte(futureTask);
} catch (InterruptedException e) {
e.printStackTrace();
}

}

/**
* 新增方法
*/
public  void pause()
{
httpService.pause();
if(futureTask!=null)
{
ThreadPoolManager.getInstance().removeTask(futureTask);
}

}
}


三、在网络与数据库框架的基础上再次封装

1、定义下载状态、优先级、停止模式

public enum  DownloadStatus {
waitting(0),

starting(1),

downloading(2),

pause(3),

finish(4),

failed(5)
;

private int value;
private   DownloadStatus(int value)
{
this.value=value;
}

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}
}


public enum Priority
{
/**
* 手动下载的优先级
*/
low(0),

/**
* 主动推送资源的手动恢复的优先级
*/
middle(1),

/**
* 主动推送资源的优先级
*/
high(2);
Priority(int value)
{
this.value = value;
}

private int value;

public int getValue()
{
return value;
}

public void setValue(int value)
{
this.value = value;
}

public static Priority getInstance(int value)
{
for (Priority priority : Priority.values())
{
if (priority.getValue() == value)
{
return priority;
}
}
return Priority.middle;
}
}


public enum DownloadStopMode
{
/**
* 后台根据下载优先级调度自动停止下载任务
*/
auto(0),

/**
* 手动停止下载任务
*/
hand(1);
DownloadStopMode(Integer value)
{
this.value = value;
}

/**
* 值
*/
private Integer value;

public Integer getValue()
{
return value;
}

public void setValue(Integer value)
{
this.value = value;
}

public static DownloadStopMode getInstance(int value)
{
for (DownloadStopMode mode : DownloadStopMode.values())
{
if (mode.getValue() == value)
{
return mode;
}
}
return DownloadStopMode.auto;
}
}


2、定义业务Bean及其基类

public class BaseEntity<T> implements Serializable{
private static final long serialVersionUID = 1L;
public BaseEntity() {
}

public T copy() {
ByteArrayOutputStream byteArrayOutputStream = null;
ObjectOutputStream objectOutputStream = null;

try {
byteArrayOutputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);

ByteArrayInputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
Object result = objectInputStream.readObject();
return (T) result;
} catch (IOException io) {
io.printStackTrace();
} catch (ClassNotFoundException classNot) {
classNot.printStackTrace();
} finally {
if(byteArrayOutputStream != null) {
try {
byteArrayOutputStream.close();
} catch (IOException io) {
io.printStackTrace();
}
}

if(objectOutputStream != null) {
try {
objectOutputStream.close();
} catch (IOException io) {
io.printStackTrace();
}
}

}

return null;
}

}


@DbTable("t_downloadInfo")
public class DownloadItemInfo extends  BaseEntity<DownloadItemInfo>  {

public long currentLength;

public long totalLength;

public  transient  HttpTask httpTask;
/**
* 下载id
*/
public Integer id;

/**
* 下载url
*/
public String url;

/**
* 下载存储的文件路径
*/
public String filePath;

/**
* 下载文件显示名
*/
public String displayName;
/**
* 下载文件总大小
*/
public Long totalLen;

/**
* 下载文件当前大小
*/
public Long currentLen;

/**
* 下载开始时间
*/
public String startTime;

/**
* 下载结束时间
*/
public String finishTime;

/**
* 用户id
*/
public String userId;

/**
* 下载任务类型
*/
public String httpTaskType;

/**
* 下载优先级
*/
public Integer priority;

/**
* 下载停止模式
*/
public Integer stopMode;

//下载的状态
public Integer status;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getDisplayName() {
return displayName;
}

public void setDisplayName(String displayName) {
this.displayName = displayName;
}

public Long getTotalLen() {
return totalLen;
}

public void setTotalLen(Long totalLen) {
this.totalLen = totalLen;
}

public Long getCurrentLen() {
return currentLen;
}

public void setCurrentLen(Long currentLen) {
this.currentLen = currentLen;
}

public void setFinishTime(String finishTime) {
this.finishTime = finishTime;
}

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}

public String getHttpTaskType() {
return httpTaskType;
}

public void setHttpTaskType(String httpTaskType) {
this.httpTaskType = httpTaskType;
}

public Integer getPriority() {
return priority;
}

public void setPriority(Integer priority) {
this.priority = priority;
}

public Integer getStopMode() {
return stopMode;
}

public void setStopMode(Integer stopMode) {
this.stopMode = stopMode;
}

public DownloadItemInfo(String url, String filePath) {
this.url = url;
this.filePath = filePath;
}

public DownloadItemInfo( ) {
}

public Integer getStatus() {
return status;
}

public void setStatus(Integer status) {
this.status = status;
}

public long getCurrentLength() {
return currentLength;
}

public void setCurrentLength(long currentLength) {
this.currentLength = currentLength;
}

public long getTotalLength() {
return totalLength;
}

public void setTotalLength(long totalLength) {
this.totalLength = totalLength;
}

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getFilePath() {
return filePath;
}

public void setFilePath(String filePath) {
this.filePath = filePath;
}

public HttpTask getHttpTask() {
return httpTask;
}

public void setHttpTask(HttpTask httpTask) {
this.httpTask = httpTask;
}

public void setStartTime(String startTime) {
this.startTime = startTime;
}
}


3、定义下载的接口

public interface IDownLitener  extends IHttpListener{

void setHttpServive(IHttpService  httpServive);

void  setCancleCalle();

void  setPuaseCallble();

}


/**
* 断点续传监听接口
*/
public interface IDownloadCallable
{

/**
* 新增下载任务的监听
*
* @param downloadId
*            下载id
*/
void onDownloadInfoAdd(int downloadId);

/**
* 删除下载任务的监听
*
* @param downloadId
*            下载id
*/
void onDownloadInfoRemove(int downloadId);

/**
* 下载状态变化
*
* @param downloadId
*            下载id
* @param status
*            下载状态
*/

void onDownloadStatusChanged(int downloadId, DownloadStatus status);

/**
* 获取了下载文件总的长度
*
* @param downloadId
*            下载id
* @param totalLength
*            下载文件总的长度
*/
void onTotalLengthReceived(int downloadId, long totalLength);

/**
* 下载进度
*
* @param downloadId
*            下载id
* @param downloadpercent
*            下载的百分比
* @param speed
*            下载速度
*/
void onCurrentSizeChanged(int downloadId, double downloadpercent, long speed);

/**
* 下载成功
*
* @param downloadId
*            下载id
*/
void onDownloadSuccess(int downloadId);

/**
* 下载失败监听
*
* @param downloadId
*            下载id
* @param errorCode
*            下载错误码
* @param errorMsg
*            下载错误信息
*/
void onDownloadError(int downloadId, int errorCode, String errorMsg);
}


public interface IDownloadServiceCallable {
void onDownloadStatusChanged(DownloadItemInfo downloadItemInfo);

void onTotalLengthReceived(DownloadItemInfo downloadItemInfo);

void onCurrentSizeChanged(DownloadItemInfo downloadItemInfo, double downLenth, long speed);

void onDownloadSuccess(DownloadItemInfo downloadItemInfo);

void onDownloadPause(DownloadItemInfo downloadItemInfo);

void onDownloadError(DownloadItemInfo downloadItemInfo, int var2, String var3);
}


4、实现数据具体操作

public class DownLoadDao extends BaseDao<DownloadItemInfo> {
/**
* 保存应该下载的集合
* 不包括已经下载成功的
*/
private List<DownloadItemInfo> downloadItemInfoList=
Collections.synchronizedList(new ArrayList<DownloadItemInfo>());

private DownloadInfoComparator downloadInfoComparator=new DownloadInfoComparator();

@Override
public String createTable() {
return "create table if not exists  t_downloadInfo(" + "id Integer primary key, " + "url TEXT not null," + "filePath TEXT not null, " + "displayName TEXT, " + "status Integer, " + "totalLen Long, " + "currentLen Long," + "startTime TEXT," + "finishTime TEXT," + "userId TEXT, " + "httpTaskType TEXT," + "priority  Integer," + "stopMode Integer," + "downloadMaxSizeKey TEXT," + "unique(filePath))";
}

@Override
public List<DownloadItemInfo> query(String sql) {
return null;
}
/**
* id
*/
/**
* 生成下载id
*
* @return 返回下载id
*/
private Integer generateRecordId()
{
int maxId = 0;
String sql = "select max(id)  from " +getTableName() ;
synchronized (DownLoadDao.class)
{
Cursor cursor = this.sqLiteDatabase.rawQuery(sql,null);
if(cursor.moveToNext())
{
String[] colmName=cursor.getColumnNames();

int index=cursor.getColumnIndex("max(id)");
if(index!=-1)
{
Object value =cursor.getInt(index);
if (value != null)
{
maxId = Integer.parseInt(String.valueOf(value));
}
}
}

}
return maxId + 1;
}

/**
* 根据下载地址和下载文件路径查找下载记录
*
* @param url
*            下载地址
* @param filePath
*            下载文件路径
* @return
*/
public DownloadItemInfo findRecord(String url, String filePath)
{
synchronized (DownLoadDao.class)
{
for (DownloadItemInfo record : downloadItemInfoList)
{
if (record.getUrl().equals(url) && record.getFilePath().equals(filePath))
{
return record;
}
}
/**
* 内存集合找不到
* 就从数据库中查找
*/
DownloadItemInfo where = new DownloadItemInfo();
where.setUrl(url);
where.setFilePath(filePath);
List<DownloadItemInfo> resultList = super.query(where);
if (resultList.size() > 0)
{
return resultList.get(0);
}
return null;
}

}

/**
* 根据 下载文件路径查找下载记录
*
*            下载地址
* @param filePath
*            下载文件路径
* @return
*/
public List<DownloadItemInfo> findRecord(String filePath)
{
synchronized (DownLoadDao.class)
{
DownloadItemInfo where = new DownloadItemInfo();
where.setFilePath(filePath);
List<DownloadItemInfo> resultList = super.query(where);
return resultList;
}

}

/**
* 添加下载记录
*
* @param url
*            下载地址
* @param filePath
*            下载文件路径
* @param displayName
*            文件显示名
* @param priority
*            小组优先级
*            TODO
* @return 下载id
*/
public int addRecrod(String url, String filePath, String displayName , int priority)
{
synchronized (DownLoadDao.class)
{
DownloadItemInfo existDownloadInfo = findRecord(url, filePath);
if (existDownloadInfo == null)
{
DownloadItemInfo record = new DownloadItemInfo();
record.setId(generateRecordId());
record.setUrl(url);
record.setFilePath(filePath);
record.setDisplayName(displayName);
record.setStatus(DownloadStatus.waitting.getValue());
record.setTotalLen(0L);
record.setCurrentLen(0L);
java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
record.setStartTime(dateFormat.format(new Date()));
record.setFinishTime("0");
record.setPriority(priority);
super.insert(record);
downloadItemInfoList.add(record);
return record.getId();
}
return -1;
}
}

/**
* 更新下载记录
*
* @param record
*            下载记录
* @return
*/
public int updateRecord(DownloadItemInfo record)
{
DownloadItemInfo where = new DownloadItemInfo();
where.setId(record.getId());
int result = 0;
synchronized (DownLoadDao.class)
{
try
{
result = super.update(record, where);
}
catch (Throwable e)
{
}
if (result > 0)
{
for (int i = 0; i < downloadItemInfoList.size(); i++)
{
if (downloadItemInfoList.get(i).getId().intValue() == record.getId())
{
downloadItemInfoList.set(i, record);
break;
}
}
}
}
return result;
}
/**
* 根据下载地址和下载文件路径查找下载记录
*
*            下载地址
* @param filePath
*            下载文件路径
* @return
*/
public DownloadItemInfo findSigleRecord(String filePath)
{
List<DownloadItemInfo> downloadInfoList = findRecord(filePath);
if(downloadInfoList.isEmpty())
{
return null;
}
return downloadInfoList.get(0);
}
/**
* 根据id查找下载记录对象
*
* @param recordId
* @return
*/
public DownloadItemInfo findRecordById(int recordId)
{
synchronized (DownLoadDao.class)
{
for (DownloadItemInfo record :downloadItemInfoList)
{
if (record.getId() == recordId)
{
return record;
}
}

DownloadItemInfo where = new DownloadItemInfo();
where.setId(recordId);
List<DownloadItemInfo> resultList = super.query(where);
if (resultList.size() > 0)
{
return resultList.get(0);
}
return null;
}

}
/**
* 根据id从内存中移除下载记录
*
* @param id
*            下载id
* @return true标示删除成功,否则false
*/
public boolean removeRecordFromMemery(int id)
{
synchronized (DownloadItemInfo.class)
{
for (int i = 0; i < downloadItemInfoList.size(); i++)
{
if (downloadItemInfoList.get(i).getId() == id)
{
downloadItemInfoList.remove(i);
break;
}
}
return true;
}
}

/**
* 比较器
*/
class DownloadInfoComparator implements Comparator<DownloadItemInfo>
{
@Override
public int compare(DownloadItemInfo lhs, DownloadItemInfo rhs)
{
return rhs.getId() - lhs.getId();
}
}
}


5、实现下载和回调的接口

public class DownLoadLitener  implements IDownLitener{

private  DownloadItemInfo downloadItemInfo;

private File file;
protected  String url;
private long breakPoint;
private IDownloadServiceCallable downloadServiceCallable;

private IHttpService httpService;
/**
* 得到主线程
*/
private Handler handler=new Handler(Looper.getMainLooper());
public DownLoadLitener(DownloadItemInfo downloadItemInfo,
IDownloadServiceCallable downloadServiceCallable,
IHttpService httpService) {
this.downloadItemInfo = downloadItemInfo;
this.downloadServiceCallable = downloadServiceCallable;
this.httpService = httpService;
this.file=new File(downloadItemInfo.getFilePath());
/**
* 得到已经下载的长度
*/
this.breakPoint=file.length();
}

/**
* 2
* @param headerMap
*/
public void addHttpHeader(Map<String,String> headerMap)
{
long length=getFile().length();
if(length>0L)
{
headerMap.put("RANGE","bytes="+length+"-");
}

}
public DownLoadLitener(DownloadItemInfo downloadItemInfo) {
this.downloadItemInfo = downloadItemInfo;
}

@Override
public void setHttpServive(IHttpService httpServive) {
this.httpService=httpServive;
}

/**
* 设置取消接口
*/
@Override
public void setCancleCalle() {

}

@Override
public void setPuaseCallble() {

}

@Override
public void onSuccess(HttpEntity httpEntity) {
InputStream inputStream = null;
try {
inputStream = httpEntity.getContent();
} catch (IOException e) {
e.printStackTrace();
}

long startTime = System.currentTimeMillis();
//用于计算每秒多少k
long speed = 0L;
//花费时间
long useTime = 0L;
//下载的长度
long getLen = 0L;
//接受的长度
long receiveLen = 0L;
boolean bufferLen = false;
//得到下载的长度
long dataLength = httpEntity.getContentLength();
//单位时间下载的字节数
long calcSpeedLen = 0L;
//总数
long totalLength = this.breakPoint + dataLength;
//更新数量
this.receviceTotalLength(totalLength);
//更新状态
this.downloadStatusChange(DownloadStatus.downloading);
byte[] buffer = new byte[512];
int count = 0;
long currentTime = System.currentTimeMillis();
BufferedOutputStream bos = null;
FileOutputStream fos = null;

try {
if (!makeDir(this.getFile().getParentFile())) {
downloadServiceCallable.onDownloadError(downloadItemInfo,1,"创建文件夹失败");
} else {
fos = new FileOutputStream(this.getFile(), true);
bos = new BufferedOutputStream(fos);
int length = 1;
while ((length = inputStream.read(buffer)) != -1) {
if (this.getHttpService().isCancle()) {
downloadServiceCallable.onDownloadError(downloadItemInfo, 1, "用户取消了");
return;
}

if (this.getHttpService().isPause()) {
downloadServiceCallable.onDownloadError(downloadItemInfo, 2, "用户暂停了");
return;
}
bos.write(buffer, 0, length);
getLen += (long) length;
receiveLen += (long) length;
calcSpeedLen += (long) length;
++count;
if (receiveLen * 10L / totalLength >= 1L || count >= 5000) {
currentTime = System.currentTimeMillis();
useTime = currentTime - startTime;
startTime = currentTime;
speed = 1000L * calcSpeedLen / useTime;
count = 0;
calcSpeedLen = 0L;
receiveLen = 0L;
//应该保存数据库
this.downloadLengthChange(this.breakPoint + getLen, totalLength, speed);
}
}
bos.close();
inputStream.close();
if (dataLength != getLen) {
downloadServiceCallable.onDownloadError(downloadItemInfo, 3, "下载长度不相等");
} else {
this.downloadLengthChange(this.breakPoint + getLen, totalLength, speed);
this.downloadServiceCallable.onDownloadSuccess(downloadItemInfo.copy());
}
}
} catch (IOException ioException) {
if (this.getHttpService() != null) {
//                this.getHttpService().abortRequest();
}
return;
} catch (Exception e) {
if (this.getHttpService() != null) {
//                this.getHttpService().abortRequest();
}
} finally {
try {
if (bos != null) {
bos.close();
}

if (httpEntity != null) {
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}

/**
* 创建文件夹的操作
* @param parentFile
* @return
*/
private boolean makeDir(File parentFile) {
return parentFile.exists()&&!parentFile.isFile()
?parentFile.exists()&&parentFile.isDirectory():
parentFile.mkdirs();
}

private void downloadLengthChange(final long downlength, final long totalLength, final long speed) {
downloadItemInfo.setCurrentLength(downlength);
if(downloadServiceCallable!=null)
{
DownloadItemInfo copyDownItenIfo=downloadItemInfo.copy();
synchronized (this.downloadServiceCallable)
{
handler.post(new Runnable() {
@Override
public void run() {
downloadServiceCallable.onCurrentSizeChanged(downloadItemInfo,(double) downlength/(double)totalLength,speed);
}
});
}

}

}

/**
* 更改下载时的状态
* @param downloading
*/
private void downloadStatusChange(DownloadStatus downloading) {
downloadItemInfo.setStatus(downloading.getValue());
final DownloadItemInfo copyDownloadItemInfo=downloadItemInfo.copy();
if(downloadServiceCallable!=null)
{
synchronized (this.downloadServiceCallable)
{
handler.post(new Runnable() {
@Override
public void run() {
downloadServiceCallable.onDownloadStatusChanged(copyDownloadItemInfo);
}
});
}
}
}

/**
* 回调  长度的变化
* @param totalLength
*/
private void receviceTotalLength(long totalLength) {
downloadItemInfo.setCurrentLength(totalLength);
final DownloadItemInfo copyDownloadItemInfo=downloadItemInfo.copy();
if(downloadServiceCallable!=null)
{
synchronized (this.downloadServiceCallable)
{
handler.post(new Runnable() {
@Override
public void run() {
downloadServiceCallable.onTotalLengthReceived(copyDownloadItemInfo);
}
});
}
}

}

@Override
public void onFail() {

}

public IHttpService getHttpService() {
return httpService;
}

public File getFile() {
return file;
}
}


public class FileDownHttpService implements IHttpService {
private static final String TAG = "FileDownHttpService";
/**
* 即将添加到请求头的信息
*/
private Map<String ,String> headerMap= Collections.synchronizedMap(new HashMap<String ,String>());
/**
* 含有请求处理的 接口
*/
private IHttpListener httpListener;

private HttpClient httpClient=new DefaultHttpClient();
private HttpGet httpPost;
private String url;

private byte[] requestDate;
/**
* httpClient获取网络的回调
*/
private  HttpRespnceHandler httpRespnceHandler=new HttpRespnceHandler();
/**
* 增加方法
*/
private AtomicBoolean pause=new AtomicBoolean(false);

@Override
public void setUrl(String url) {
this.url=url;
}

@Override
public void excute() {
httpPost=new HttpGet(url);
constrcutHeader();
//        ByteArrayEntity byteArrayEntity=new ByteArrayEntity(requestDate);
//        httpPost.setEntity(byteArrayEntity);
try {
httpClient.execute(httpPost,httpRespnceHandler);
} catch (IOException e) {
httpListener.onFail();
}
}

/**
* 1
*/
private void constrcutHeader() {
Iterator iterator=headerMap.keySet().iterator();
while (iterator.hasNext())
{
String key= (String) iterator.next();
String value=headerMap.get(key);
Log.i(TAG," 请求头信息  "+key+"  value "+value);
httpPost.addHeader(key,value);
}
}

public Map<String, String> getHeaderMap() {
return headerMap;
}

@Override
public void setHttpListener(IHttpListener httpListener) {
this.httpListener=httpListener;
}

@Override
public void setRequestData(byte[] requestData) {
this.requestDate=requestData;
}

@Override
public void pause() {
pause.compareAndSet(false,true);
}

@Override
public Map<String, String> getHttpHeadMap() {
return headerMap;
}

@Override
public boolean cancle() {
return false;
}

@Override
public boolean isCancle() {
return false;
}
@Override
public boolean isPause() {
return pause.get();
}

private class HttpRespnceHandler extends BasicResponseHandler
{
@Override
public String handleResponse(HttpResponse response) throws ClientProtocolException {
//响应吗
int code=response.getStatusLine().getStatusCode();
if(code==200||206==code)
{
httpListener.onSuccess(response.getEntity());
}else
{
ListView list;
httpListener.onFail();
}

return null;
}
}
}


6、将整个逻辑进行封装、链接、启动,形成调用工具类

public class DownFileManager implements IDownloadServiceCallable {
private static final String TAG ="DownFileManager " ;
//    private  static
private byte[] lock=new byte[0];
DownLoadDao downLoadDao= BaseDaoFactory.getInstance().
getDataHelper(DownLoadDao.class,DownloadItemInfo.class);
java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
/**
* 观察者模式
*/
private final List<IDownloadCallable> applisteners = new CopyOnWriteArrayList<IDownloadCallable>();

/**
* 正在下载的所有任务
*/
private static List<DownloadItemInfo> downloadFileTaskList = new CopyOnWriteArrayList();

Handler handler=new Handler(Looper.getMainLooper());

public int download(String url)
{
String[] preFix=url.split("/");
return this.download(url,Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+preFix[preFix.length-1]);
}
public int download(String url, String filePath )
{
String[] preFix=url.split("/");
String displayName=preFix[preFix.length-1];
return this.download(url,filePath,displayName);
}
public int download(String url, String filePath, String displayName)
{
return this.download(url,filePath,displayName,Priority.middle);
}

public int download(String url, String filePath,
String displayName , Priority priority ) {

if(priority==null)
{
priority=Priority.low;
}
File file=new File(filePath);
DownloadItemInfo downloadItemInfo=null;

downloadItemInfo=downLoadDao.findRecord(url,filePath);
//没下载
if(downloadItemInfo==null)
{
/**
* 根据文件路径查找
*/
List<DownloadItemInfo> samesFile=downLoadDao.findRecord(filePath);
/**
* 大于0  表示下载
*/
if(samesFile.size()>0)
{
DownloadItemInfo sameDown=samesFile.get(0);
if(sameDown.getCurrentLen()==sameDown.getTotalLen())
{
synchronized (applisteners)
{
for (IDownloadCallable downloadCallable:applisteners)
{
downloadCallable.onDownloadError(sameDown.getId(),2,"文件已经下载了");
}
}

}
}
/**---------------------------------------------
* 插入数据库
* 可能插入失败
* 因为filePath  和id是独一无二的  在数据库建表时已经确定了
*/
int recrodId=downLoadDao.addRecrod(url,filePath,displayName,priority.getValue());
if(recrodId!=-1)
{
synchronized (applisteners)
{
for (IDownloadCallable downloadCallable:applisteners)
{
//通知应用层  数据库被添加了
downloadCallable.onDownloadInfoAdd(downloadItemInfo.getId());
}
}
}
//插入失败时,再次进行查找,确保能查得到
else
{
//插入
downloadItemInfo=downLoadDao.findRecord(url,filePath);
}
}
/**-----------------------------------------------
* 括号写错了  放在外面
*
* 是否正在下载`
*/
if(isDowning(file.getAbsolutePath()))
{
synchronized (applisteners)
{
for (IDownloadCallable downloadCallable:applisteners)
{
downloadCallable.onDownloadError(downloadItemInfo.getId(),4,"正在下载,请不要重复添加");
}
}
return downloadItemInfo.getId();
}

if(downloadItemInfo!=null)
{
downloadItemInfo.setPriority(priority.getValue());
//添加----------------------------------------------------
downloadItemInfo.setStopMode(DownloadStopMode.auto.getValue());

//判断数据库存的 状态是否是完成
if(downloadItemInfo.getStatus()!= DownloadStatus.finish.getValue())
{
if(downloadItemInfo.getTotalLen()==0L||file.length()==0L)
{
Log.i(TAG,"还未开始下载");
//----------------------删除--------------------
downloadItemInfo.setStatus(DownloadStatus.failed.getValue());
}
//判断数据库中 总长度是否等于文件长度
if(downloadItemInfo.getTotalLen()==file.length()&&downloadItemInfo.getTotalLen()!=0)
{
downloadItemInfo.setStatus(DownloadStatus.finish.getValue());
synchronized (applisteners)
{
for (IDownloadCallable downloadCallable:applisteners)
{
try {
downloadCallable.onDownloadError(downloadItemInfo.getId(),4,"已经下载了");
}catch (Exception e)
{
}
}
}
}
}
//------------------添加--------
else
{
if(!file.exists()||(downloadItemInfo.getTotalLen()!=downloadItemInfo.getCurrentLen()))
{
downloadItemInfo.setStatus(DownloadStatus.failed.getValue());
}
}
/**
*
* 更新
*/
downLoadDao.updateRecord(downloadItemInfo);
//移到括号里面来----------------------------------------------------
/**
* 判断是否已经下载完成
*/
if(downloadItemInfo.getStatus()==DownloadStatus.finish.getValue())
{
Log.i(TAG,"已经下载完成  回调应用层");
final int downId=downloadItemInfo.getId();
synchronized (applisteners)
{
handler.post(new Runnable() {
@Override
public void run() {
for (IDownloadCallable downloadCallable:applisteners)
{
downloadCallable.onDownloadStatusChanged(downId,DownloadStatus.finish);
}
}
});
}
downLoadDao.removeRecordFromMemery(downId);
return downloadItemInfo.getId();
}//之前的下载 状态为暂停状态
List<DownloadItemInfo> allDowning=downloadFileTaskList;
//当前下载不是最高级  则先退出下载
if(priority!=Priority.high)
{
for(DownloadItemInfo downling:allDowning)
{
//从下载表中  获取到全部正在下载的任务
downling=downLoadDao.findSigleRecord(downling.getFilePath());

if(downling!=null&&downling.getPriority()==Priority.high.getValue())
{

/**
*     更改---------
*     当前下载级别不是最高级 传进来的是middle    但是在数据库中查到路径一模一样 的记录   所以他也是最高级------------------------------
*     比如 第一次下载是用最高级下载,app闪退后,没有下载完成,第二次传的是默认级别,这样就应该是最高级别下载

*/
if (downling.getFilePath().equals(downloadItemInfo.getFilePath()))
{
break;
}
else
{
return downloadItemInfo.getId();
}
//                        if(downloadItemInfo.getFilePath().equals(downling.getFilePath()))
//                        {
//                            return downloadItemInfo.getId();
//                        }
}
}
}
//
reallyDown(downloadItemInfo);
if(priority==Priority.high||priority== Priority.middle)
{
synchronized (allDowning)
{
for (DownloadItemInfo downloadItemInfo1:allDowning)
{
if(!downloadItemInfo.getFilePath().equals(downloadItemInfo1.getFilePath()))
{
DownloadItemInfo downingInfo=downLoadDao.findSigleRecord(downloadItemInfo1.getFilePath());
if(downingInfo!=null)
{
pause(downloadItemInfo.getId(),DownloadStopMode.auto);
}
}
}
}
return downloadItemInfo.getId();
}
}

return  -1;
}

/**
* 停止
* @param downloadId
* @param mode
*/
public void pause(int downloadId, DownloadStopMode mode)
{
if (mode == null)
{
mode = DownloadStopMode.auto;
}
final DownloadItemInfo downloadInfo =downLoadDao.findRecordById(downloadId);
if (downloadInfo != null)
{
// 更新停止状态
if (downloadInfo != null)
{
downloadInfo.setStopMode(mode.getValue());
downloadInfo.setStatus(DownloadStatus.pause.getValue());
downLoadDao.updateRecord(downloadInfo);
}
for (DownloadItemInfo downing:downloadFileTaskList)
{
if(downloadId==downing.getId())
{
downing.getHttpTask().pause();
}
}
}
}

/**
* 判断当前是否正在下载
*
* @param absolutePath
* @return
*/
private boolean isDowning(String absolutePath) {
for (DownloadItemInfo downloadItemInfo:downloadFileTaskList)
{
if(downloadItemInfo.getFilePath().equals(absolutePath))
{
return true;
}
}
return false;
}

/**
* 添加观察者
* @param downloadCallable
*/
public void setDownCallable(IDownloadCallable downloadCallable)
{
synchronized (applisteners)
{
applisteners.add(downloadCallable);
}

}

/**
* 下载
*/
public DownloadItemInfo reallyDown(DownloadItemInfo downloadItemInfo)
{
synchronized (lock)
{
//实例化DownloadItem
RequestHodler requestHodler=new RequestHodler();
//设置请求下载的策略
IHttpService httpService=new FileDownHttpService();
//得到请求头的参数 map
Map<String,String> map=httpService.getHttpHeadMap();
/**
* 处理结果的策略
*/
IHttpListener httpListener=new DownLoadLitener(downloadItemInfo,this,httpService);

requestHodler.setHttpListener(httpListener);
requestHodler.setHttpService(httpService);
/**
*  bug  url
*/
requestHodler.setUrl(downloadItemInfo.getUrl());

HttpTask httpTask=new HttpTask(requestHodler);
downloadItemInfo.setHttpTask(httpTask);

/**
* 添加
*/
downloadFileTaskList.add(downloadItemInfo);
httpTask.start();
}
return downloadItemInfo;

}

@Override
public void onDownloadStatusChanged(DownloadItemInfo downloadItemInfo) {

}

@Override
public void onTotalLengthReceived(DownloadItemInfo downloadItemInfo) {

}

@Override
public void onCurrentSizeChanged(DownloadItemInfo downloadItemInfo, double downLenth, long speed) {
Log.i(TAG,"下载速度:"+ speed/1000 +"k/s");
Log.i(TAG,"-----路径  "+ downloadItemInfo.getFilePath()+"  下载长度  "+downLenth+"   速度  "+speed);
}

@Override
public void onDownloadSuccess(DownloadItemInfo downloadItemInfo) {
Log.i(TAG,"下载成功    路劲  "+ downloadItemInfo.getFilePath()+"  url "+ downloadItemInfo.getUrl());

}

@Override
public void onDownloadPause(DownloadItemInfo downloadItemInfo) {
}

@Override
public void onDownloadError(DownloadItemInfo downloadItemInfo, int var2, String var3) {

}
}


四、调用

DownFileManager downFileService=new DownFileManager();     downFileService.download("http://gdown.baidu.com/data/wisegame/8be18d2c0dc8a9c9/WPSOffice_177.apk");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐