版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】Android中怎么實現(xiàn)多任務(wù)多線程斷點下載功能
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;
/**
*
業(yè)務(wù)bean
*
*/
public
class
FileService
{
private
DBOpenHelper
openHelper;
public
FileService(Context
context)
{
openHelper
=
new
DBOpenHelper(context);
}
/**
*
獲取每條線程已經(jīng)下載的文件長度
*
@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;
}
/**
*
保存每條線程已經(jīng)下載的文件長度
*
@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();
}
/**
*
實時更新每條線程已經(jīng)下載的文件長度
*
@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();
}
/**
*
當(dāng)文件下載完成后,刪除對應(yīng)的下載記錄
*
@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;
/*
線程數(shù)
*/
private
SmartDownloadThread[]
threads;
/*
本地保存文件
*/
private
File
saveFile;
/*
緩存各線程下載的長度*/
private
Map<Integer,
Integer>
data
=
new
ConcurrentHashMap<Integer,
Integer>();
/*
每條線程下載的長度
*/
private
int
block;
/*
下載路徑
*/
private
String
downloadUrl;
/**
*
獲取線程數(shù)
*/
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);
}
/**
*
構(gòu)建文件下載器
*
@param
downloadUrl
下載路徑
*
@param
fileSaveDir
文件保存目錄
*
@param
threadNum
下載線程數(shù)
*/
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();//根據(jù)響應(yīng)獲取文件大小
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("已經(jīng)下載的長度"+
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";//默認(rèn)取一個文件名
}
return
filename;
}
/**
*
開始下載文件
*
@param
listener
監(jiān)聽下載數(shù)量的變化,如果不需要了解實時下載的數(shù)量,可以設(shè)置為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();//清除數(shù)據(jù)
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){
//該線程未完成下載時,繼續(xù)下載
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)
{//
循環(huán)判斷是否下載完畢
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響應(yīng)頭字段
*
@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;//結(jié)束位置
http.setRequestProperty("Range",
"bytes="
+
startPos
+
"-"+
endPos);//設(shè)置獲取實體數(shù)據(jù)的范圍
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;
}
/**
*
已經(jīng)下載的內(nèi)容大小
*
@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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2023-2024學(xué)年河北省承德市高二上學(xué)期開學(xué)英語試題(解析版)
- 成長作文之成長的故事1000字作文
- 2024年飛機燃油系統(tǒng)項目發(fā)展計劃
- 2024年小型生物質(zhì)氣化發(fā)電裝置項目合作計劃書
- 2024年TFT-LCD用偏光片項目發(fā)展計劃
- 2024年上門服務(wù)項目建議書
- 2024年群路密碼機系列合作協(xié)議書
- 2024年旋片真空泵項目合作計劃書
- 2024年農(nóng)業(yè)運輸機械合作協(xié)議書
- 承包經(jīng)營合同書(模板)
- 公開課聽課教師簽到表
- 開展新技術(shù)、新項目科室內(nèi)討論記錄
- 高中語文必修《采薇》說課稿講評稿
- 綠色插畫風(fēng)時事新聞播報PPT通用
- 道德與法治《健康看電視》優(yōu)秀課件
- 急性肺栓塞的急救與護理-課件
- 初中化學(xué)中考其他-如何設(shè)置標(biāo)準(zhǔn)試卷格式
- 理療試題(含答案)
- 高中語文必修上冊8.《夢游天姥吟留別》《行路難(其一)》群文閱讀課件29張
- 管道內(nèi)部清潔度質(zhì)量控制管理規(guī)定
- 降低鍋爐除氧器蒸汽耗用
評論
0/150
提交評論