版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】Android中怎么实现多任务多线程断点下载功能
package
com.smart.db;
import
java.util.HashMap;
import
java.util.Map;
import
android.content.Context;
import
android.database.Cursor;
import
android.database.sqlite.SQLiteDatabase;
/**
*
业务bean
*
*/
public
class
FileService
{
private
DBOpenHelper
openHelper;
public
FileService(Context
context)
{
openHelper
=
new
DBOpenHelper(context);
}
/**
*
获取每条线程已经下载的文件长度
*
@param
path
*
@return
*/
public
Map<Integer,
Integer>
getData(String
path){
SQLiteDatabase
db
=
openHelper.getReadableDatabase();
Cursor
cursor
=
db.rawQuery("select
threadid,
downlength
from
SmartFileDownlog
where
downpath=?",
new
String[]{path});
Map<Integer,
Integer>
data
=
new
HashMap<Integer,
Integer>();
while(cursor.moveToNext()){
data.put(cursor.getInt(0),
cursor.getInt(1));
}
cursor.close();
db.close();
return
data;
}
/**
*
保存每条线程已经下载的文件长度
*
@param
path
*
@param
map
*/
public
void
save(String
path,
Map<Integer,
Integer>
map){//int
threadid,
int
position
SQLiteDatabase
db
=
openHelper.getWritableDatabase();
db.beginTransaction();
try{
for(Map.Entry<Integer,
Integer>
entry
:
map.entrySet()){
db.execSQL("insert
into
SmartFileDownlog(downpath,
threadid,
downlength)
values(?,?,?)",
new
Object[]{path,
entry.getKey(),
entry.getValue()});
}
db.setTransactionSuccessful();
}finally{
db.endTransaction();
}
db.close();
}
/**
*
实时更新每条线程已经下载的文件长度
*
@param
path
*
@param
map
*/
public
void
update(String
path,
Map<Integer,
Integer>
map){
SQLiteDatabase
db
=
openHelper.getWritableDatabase();
db.beginTransaction();
try{
for(Map.Entry<Integer,
Integer>
entry
:
map.entrySet()){
db.execSQL("update
SmartFileDownlog
set
downlength=?
where
downpath=?
and
threadid=?",
new
Object[]{entry.getValue(),
path,
entry.getKey()});
}
db.setTransactionSuccessful();
}finally{
db.endTransaction();
}
db.close();
}
/**
*
当文件下载完成后,删除对应的下载记录
*
@param
path
*/
public
void
delete(String
path){
SQLiteDatabase
db
=
openHelper.getWritableDatabase();
db.execSQL("delete
from
SmartFileDownlog
where
downpath=?",
new
Object[]{path});
db.close();
}
}
package
com.smart.impl;
import
java.io.File;
import
java.io.RandomAccessFile;
import
.HttpURLConnection;
import
.URL;
import
java.util.LinkedHashMap;
import
java.util.Map;
import
java.util.UUID;
import
java.util.concurrent.ConcurrentHashMap;
import
java.util.regex.Matcher;
import
java.util.regex.Pattern;
import
android.content.Context;
import
android.util.Log;
import
com.smart.db.FileService;
/**
*
文件下载器
*
@author
lihuoming@
*/
public
class
SmartFileDownloader
{
private
static
final
String
TAG
=
"SmartFileDownloader";
private
Context
context;
private
FileService
fileService;
/*
已下载文件长度
*/
private
int
downloadSize
=
0;
/*
原始文件长度
*/
private
int
fileSize
=
0;
/*
线程数
*/
private
SmartDownloadThread[]
threads;
/*
本地保存文件
*/
private
File
saveFile;
/*
缓存各线程下载的长度*/
private
Map<Integer,
Integer>
data
=
new
ConcurrentHashMap<Integer,
Integer>();
/*
每条线程下载的长度
*/
private
int
block;
/*
下载路径
*/
private
String
downloadUrl;
/**
*
获取线程数
*/
public
int
getThreadSize()
{
return
threads.length;
}
/**
*
获取文件大小
*
@return
*/
public
int
getFileSize()
{
return
fileSize;
}
/**
*
累计已下载大小
*
@param
size
*/
protected
synchronized
void
append(int
size)
{
downloadSize
+=
size;
}
/**
*
更新指定线程最后下载的位置
*
@param
threadId
线程id
*
@param
pos
最后下载的位置
*/
protected
void
update(int
threadId,
int
pos)
{
this.data.put(threadId,
pos);
}
/**
*
保存记录文件
*/
protected
synchronized
void
saveLogFile()
{
this.fileService.update(this.downloadUrl,
this.data);
}
/**
*
构建文件下载器
*
@param
downloadUrl
下载路径
*
@param
fileSaveDir
文件保存目录
*
@param
threadNum
下载线程数
*/
public
SmartFileDownloader(Context
context,
String
downloadUrl,
File
fileSaveDir,
int
threadNum)
{
try
{
this.context
=
context;
this.downloadUrl
=
downloadUrl;
fileService
=
new
FileService(this.context);
URL
url
=
new
URL(this.downloadUrl);
if(!fileSaveDir.exists())
fileSaveDir.mkdirs();
this.threads
=
new
SmartDownloadThread[threadNum];
HttpURLConnection
conn
=
(HttpURLConnection)
url.openConnection();
conn.setConnectTimeout(5*1000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept",
"image/gif,
image/jpeg,
image/pjpeg,
image/pjpeg,
application/x-shockwave-flash,
application/xaml+xml,
application/vnd.ms-xpsdocument,
application/x-ms-xbap,
application/x-ms-application,
application/vnd.ms-excel,
application/vnd.ms-powerpoint,
application/msword,
*/*");
conn.setRequestProperty("Accept-Language",
"zh-CN");
conn.setRequestProperty("Referer",
downloadUrl);
conn.setRequestProperty("Charset",
"UTF-8");
conn.setRequestProperty("User-Agent",
"Mozilla/4.0
(compatible;
MSIE
8.0;
Windows
NT
5.2;
Trident/4.0;
.NET
CLR
1.1.4322;
.NET
CLR
2.0.50727;
.NET
CLR
3.0.04506.30;
.NET
CLR
3.0.4506.2152;
.NET
CLR
3.5.30729)");
conn.setRequestProperty("Connection",
"Keep-Alive");
conn.connect();
printResponseHeader(conn);
if
(conn.getResponseCode()==200)
{
this.fileSize
=
conn.getContentLength();//根据响应获取文件大小
if
(this.fileSize
<=
0)
throw
new
RuntimeException("Unkown
file
size
");
String
filename
=
getFileName(conn);
this.saveFile
=
new
File(fileSaveDir,
filename);/*
保存文件
*/
Map<Integer,
Integer>
logdata
=
fileService.getData(downloadUrl);
if(logdata.size()>0){
for(Map.Entry<Integer,
Integer>
entry
:
logdata.entrySet())
data.put(entry.getKey(),
entry.getValue());
}
this.block
=
(this.fileSize
%
this.threads.length)==0?
this.fileSize
/
this.threads.length
:
this.fileSize
/
this.threads.length
+
1;
if(this.data.size()==this.threads.length){
for
(int
i
=
0;
i
<
this.threads.length;
i++)
{
this.downloadSize
+=
this.data.get(i+1);
}
print("已经下载的长度"+
this.downloadSize);
}
}else{
throw
new
RuntimeException("server
no
response
");
}
}
catch
(Exception
e)
{
print(e.toString());
throw
new
RuntimeException("don't
connection
this
url");
}
}
/**
*
获取文件名
*/
private
String
getFileName(HttpURLConnection
conn)
{
String
filename
=
this.downloadUrl.substring(this.downloadUrl.lastIndexOf('/')
+
1);
if(filename==null
||
"".equals(filename.trim())){//如果获取不到文件名称
for
(int
i
=
0;;
i++)
{
String
mine
=
conn.getHeaderField(i);
if
(mine
==
null)
break;
if("content-disposition".equals(conn.getHeaderFieldKey(i).toLowerCase())){
Matcher
m
=
Ppile(".*filename=(.*)").matcher(mine.toLowerCase());
if(m.find())
return
m.group(1);
}
}
filename
=
UUID.randomUUID()+
".tmp";//默认取一个文件名
}
return
filename;
}
/**
*
开始下载文件
*
@param
listener
监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null
*
@return
已下载文件大小
*
@throws
Exception
*/
public
int
download(SmartDownloadProgressListener
listener)
throws
Exception{
try
{
RandomAccessFile
randOut
=
new
RandomAccessFile(this.saveFile,
"rw");
if(this.fileSize>0)
randOut.setLength(this.fileSize);
randOut.close();
URL
url
=
new
URL(this.downloadUrl);
if(this.data.size()
!=
this.threads.length){
this.data.clear();//清除数据
for
(int
i
=
0;
i
<
this.threads.length;
i++)
{
this.data.put(i+1,
0);
}
}
for
(int
i
=
0;
i
<
this.threads.length;
i++)
{
int
downLength
=
this.data.get(i+1);
if(downLength
<
this.block
&&
this.downloadSize<this.fileSize){
//该线程未完成下载时,继续下载
this.threads
=
new
SmartDownloadThread(this,
url,
this.saveFile,
this.block,
this.data.get(i+1),
i+1);
this.threads.setPriority(7);
this.threads.start();
}else{
this.threads
=
null;
}
}
this.fileService.save(this.downloadUrl,
this.data);
boolean
notFinish
=
true;//下载未完成
while
(notFinish)
{//
循环判断是否下载完毕
Thread.sleep(900);
notFinish
=
false;//假定下载完成
for
(int
i
=
0;
i
<
this.threads.length;
i++){
if
(this.threads
!=
null
&&
!this.threads.isFinish())
{
notFinish
=
true;//下载没有完成
if(this.threads.getDownLength()
==
-1){//如果下载失败,再重新下载
this.threads
=
new
SmartDownloadThread(this,
url,
this.saveFile,
this.block,
this.data.get(i+1),
i+1);
this.threads.setPriority(7);
this.threads.start();
}
}
}
if(listener!=null)
listener.onDownloadSize(this.downloadSize);
}
fileService.delete(this.downloadUrl);
}
catch
(Exception
e)
{
print(e.toString());
throw
new
Exception("file
download
fail");
}
return
this.downloadSize;
}
/**
*
获取Http响应头字段
*
@param
http
*
@return
*/
public
static
Map<String,
String>
getHttpResponseHeader(HttpURLConnection
http)
{
Map<String,
String>
header
=
new
LinkedHashMap<String,
String>();
for
(int
i
=
0;;
i++)
{
String
mine
=
http.getHeaderField(i);
if
(mine
==
null)
break;
header.put(http.getHeaderFieldKey(i),
mine);
}
return
header;
}
/**
*
打印Http头字段
*
@param
http
*/
public
static
void
printResponseHeader(HttpURLConnection
http){
Map<String,
String>
header
=
getHttpResponseHeader(http);
for(Map.Entry<String,
String>
entry
:
header.entrySet()){
String
key
=
entry.getKey()!=null
?
entry.getKey()+
":"
:
"";
print(key+
entry.getValue());
}
}
//打印日志
private
static
void
print(String
msg){
Log.i(TAG,
msg);
}
}
package
com.smart.impl;
import
java.io.File;
import
java.io.InputStream;
import
java.io.RandomAccessFile;
import
.HttpURLConnection;
import
.URL;
import
android.util.Log;
public
class
SmartDownloadThread
extends
Thread
{
private
static
final
String
TAG
=
"SmartDownloadThread";
private
File
saveFile;
private
URL
downUrl;
private
int
block;
/*
*下载开始位置
*/
private
int
threadId
=
-1;
private
int
downLength;
private
boolean
finish
=
false;
private
SmartFileDownloader
downloader;
public
SmartDownloadThread(SmartFileDownloader
downloader,
URL
downUrl,
File
saveFile,
int
block,
int
downLength,
int
threadId)
{
this.downUrl
=
downUrl;
this.saveFile
=
saveFile;
this.block
=
block;
this.downloader
=
downloader;
this.threadId
=
threadId;
this.downLength
=
downLength;
}
@Override
public
void
run()
{
if(downLength
<
block){//未下载完成
try
{
HttpURLConnection
http
=
(HttpURLConnection)
downUrl.openConnection();
http.setConnectTimeout(5
*
1000);
http.setRequestMethod("GET");
http.setRequestProperty("Accept",
"image/gif,
image/jpeg,
image/pjpeg,
image/pjpeg,
application/x-shockwave-flash,
application/xaml+xml,
application/vnd.ms-xpsdocument,
application/x-ms-xbap,
application/x-ms-application,
application/vnd.ms-excel,
application/vnd.ms-powerpoint,
application/msword,
*/*");
http.setRequestProperty("Accept-Language",
"zh-CN");
http.setRequestProperty("Referer",
downUrl.toString());
http.setRequestProperty("Charset",
"UTF-8");
int
startPos
=
block
*
(threadId
-
1)
+
downLength;//开始位置
int
endPos
=
block
*
threadId
-1;//结束位置
http.setRequestProperty("Range",
"bytes="
+
startPos
+
"-"+
endPos);//设置获取实体数据的范围
http.setRequestProperty("User-Agent",
"Mozilla/4.0
(compatible;
MSIE
8.0;
Windows
NT
5.2;
Trident/4.0;
.NET
CLR
1.1.4322;
.NET
CLR
2.0.50727;
.NET
CLR
3.0.04506.30;
.NET
CLR
3.0.4506.2152;
.NET
CLR
3.5.30729)");
http.setRequestProperty("Connection",
"Keep-Alive");
InputStream
inStream
=
http.getInputStream();
byte[]
buffer
=
new
byte[1024];
int
offset
=
0;
print("Thread
"
+
this.threadId
+
"
start
download
from
position
"+
startPos);
RandomAccessFile
threadfile
=
new
RandomAccessFile(this.saveFile,
"rwd");
threadfile.seek(startPos);
while
((offset
=
inStream.read(buffer,
0,
1024))
!=
-1)
{
threadfile.write(buffer,
0,
offset);
downLength
+=
offset;
downloader.update(this.threadId,
downLength);
downloader.saveLogFile();
downloader.append(offset);
}
threadfile.close();
inStream.close();
print("Thread
"
+
this.threadId
+
"
download
finish");
this.finish
=
true;
}
catch
(Exception
e)
{
this.downLength
=
-1;
print("Thread
"+
this.threadId+
":"+
e);
}
}
}
private
static
void
print(String
msg){
Log.i(TAG,
msg);
}
/**
*
下载是否完成
*
@return
*/
public
boolean
isFinish()
{
return
finish;
}
/**
*
已经下载的内容大小
*
@return
如果返回值为-1,代表下载失败
*/
public
long
getDownLength()
{
return
downLength;
}
}
package
com.smart.activoty.download;
import
java.io.File;
import
android.app.Activity;
import
android.os.Bundle;
import
android.os.Environment;
import
android.os.Handler;
import
android.os.Message;
import
android.view.View;
import
android.widget.Button;
import
android.widget.EditText;
import
android.widget.ProgressBar;
import
android.widget.TextView;
import
android.widget.Toast;
import
com.smart.impl.SmartDownloadProgressListener;
import
com.smart.impl.SmartFileDownloader;
public
class
SmartDownloadActivity
extends
Activity
{
private
ProgressBar
downloadbar;
private
EditText
pathText;
private
TextView
resultView;
private
Handler
handler
=
new
Handler(){
@Override//信息
public
void
handleMessage(Message
msg)
{
switch
(msg.what)
{
case
1:
int
size
=
msg.getData().getInt("size");
downloadbar.setProgress(size);
float
result
=
(float)downloadbar.getProgress()/
(float)downloadbar.getMax();
int
p
=
(int)(result*100);
resultView.setText(p+"%");
if(downloadbar.getProgress()==downloadbar.getMax())
Toast.makeText(SmartDownloadActivity.this,
R.string.success,
1).show();
break;
case
-1:
Toast.makeText(SmartDownloadActivity.this,
R.string.error,
1).show();
break;
}
}
};
@Override
public
void
onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button
button
=
(Button)this.findViewById(R.id.button);
downlo
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 普外科微创手术护理
- 养老护理员职业素养与伦理
- 2025年公共卫生监测与评估服务合同协议
- 环保工程治理成果承诺书6篇
- 2026年杭州市西湖区政府直属国有企业招聘备考题库及答案详解(易错题)
- 2026年佛山市南海区国有资产监督管理局财务总监招聘备考题库及答案详解参考
- 2026年长虹镇卫生院招聘护士1名备考题库及完整答案详解1套
- 深圳北理莫斯科大学2026年汉语中心招聘备考题库及答案详解一套
- 采购需求与分类工具物料采购清单版
- 驾驶员招聘合同范本
- 木门工程售后方案(3篇)
- 2025至2030中国淡竹叶行业发展分析及产业运行态势及投资规划深度研究报告
- 电工技能实训试题及答案
- 挂名监事免责协议书模板
- 宁波职高高一数学试卷
- 2025-2026学年苏教版(2024)小学数学二年级上册(全册)教学设计(附目录P226)
- 分布式光伏电站运维管理与考核体系
- HY/T 0457-2024蓝碳生态系统碳储量调查与评估技术规程海草床
- 幼儿园食品储存安全自查报告的范文
- 公共政策概论-004-国开机考复习资料
- 2025至2030中国船用防冻剂行业发展趋势分析与未来投资战略咨询研究报告
评论
0/150
提交评论