聲明:在保證本文完整的狀況下可自由轉載!html
前言java
本文pdf下載連接android
配套視頻鏈接程序員
國士工做室是一支專一於提供一站式的Android、HTML五、Hadoop企業級軟件、培訓、諮詢培訓專家,致力於作中國最棒的Android、HTML五、Hadoop程序開發機構,提供最棒的Android、HTML五、Hadoop企業級開發培訓服務apache
企業培訓和開發合做官方聯繫方式:編程
電話:18610086859設計模式
Email:hiheartfirst@gmail.com數組
QQ:1740415547瀏覽器
QQ羣:175189001緩存
國士工做室 有你更美好!
其創始人王家林的信息:
Android架構師、高級工程師、諮詢顧問、培訓專家
通曉Android、HTML五、Hadoop,迷戀英語播音和健美
致力於Android和HTML5軟、硬、雲整合,精通Android安全。
國內最先(2007年)從事於Android系統移植、軟硬整合、框架修改、應用程序軟件開發以及Android系統測試和應用軟件測試的技術專家和技術創業人員之一。
HTML5技術領域的最先實踐者(2009年)之一,成功爲多個機構實現多款自定義HTML5瀏覽器,參與某知名的HTML5瀏覽器研發;
Tel: 18610086859
若立志成爲Android高手,若有耐心,「一瓶一鉢足矣」。
「天下事有難易乎?爲之,則難者亦易矣;不爲,則易者亦難矣。人之爲學有難易乎?學之,則難者亦易矣;不學,則易者亦難矣。」想成爲Android高手?這可不是想象中寫幾行代碼那麼容易的事情,但也不是不可實現。
如何作?
1,學會懶惰!奇怪吧?可是,你必定也據說過和感覺過這個世界某種程度上是由懶人推進的,生命在於懶惰,懶人創造世界。固然,懶惰也是真的傻傻的呆在那裏什麼都不作,而是說要善於想出作事情的更好的方式,這樣就能夠節約大量的時間,也就有更多的機會懶惰了,同事也懶出了境界。在Android中如何懶惰?《如何成爲Android高手》一文就如何在Android中學會懶惰和朋友們進行了分享。
2,精通Android體系架構、MVC、常見的設計模式、控制反轉(IoC):這一點難嗎?「學之,則難者亦易矣;不學,則易者亦難矣。」
3,編寫可重用、可擴展、可維護、靈活性高的代碼:Android應用程序開發的使用純粹面向對象的Java做爲開發語言,天然也就繼承了關於Java關於面向對象的優秀想思想,如何作?《如何成爲Android高手》一文就如何在Android中編寫可重用、可擴展、可維護、靈活性高的代碼和朋友們進行了分享。
4,高效的編寫高效的代碼:高效的編寫代碼和編寫高效的代碼好像天生就是死敵。彷佛開發速度上去了,程序的執行效率就下去了;程序的執行效率上去,開發速度就下去了。如何解決兩者的忙着,請聽《如何成爲Android高手》一文想你們娓娓道來。
5,學會至少一門服務器端開發技術:沒搞錯吧,成爲Android高手還須要學習服務端開發技術?對,須要!《如何成爲Android高手》一文就該問題和你們進行了分享。
「蜀之鄙,有二僧:其一貧,其一富。貧者語於富者曰:"吾欲之南海,何如?"富者曰:"子何恃而往?"曰:"吾一瓶一鉢足矣。"富者曰:"吾數年來欲買舟而下,猶未能也。子何恃而往!"越明年,貧者自南海還,以告富者,富者有慚色。西蜀之去南海,不知幾千裏也,僧富者不能至,而貧者至之,人之立志,顧不如蜀鄙之僧哉 」
若立志成爲Android高手,若有耐心,「一瓶一鉢足矣」。
正文
關於國士工做室
咱們(國士工做室)是一支專一於Android平臺企業級應用開發的技術團隊,對娛樂多媒體應用有着深入的理解及研發能力,致力服務於企業用戶。爲音視頻等娛樂多媒體網站、門戶網站、SNS、論壇、電子商務等傳統網絡應用向移動互聯網發展提供解決方案和技術支持,爲企業提供Android培訓服務等多種業務。
咱們尤爲擅長於提供從Android客戶端到服務端的一站式解決方案和技術支持,服務端能夠採用Java EE,也能夠採用輕量級流行的LAMP技術體系。目前,研發出了比KU六、優酷更增強大和完善的Android視頻網站娛樂多媒體客戶端軟件,並在持續升級中。
目前,咱們正在務實而卓有成效的與音視頻等娛樂多媒體網站、門戶網站、SNS、論壇、電子商務等傳統網絡服務商合做,發展迅速,渴望有志之士的加入,和咱們一塊兒爲成爲世界最好的Android軟件開發和諮詢、培訓公司而奮鬥,爲移動互聯網和智能手機時代貢獻力量!
聯繫咱們
電話:18610086859
Email:hiheartfirst@gmail.com guoshiandroid@gmail.com
QQ:1740415547
博客: http://www.cnblogs.com/guoshiandroid/
注意:該文檔參考和使用了網絡上的不少免費開放的內容,並以避免費開放的方式發佈,但願爲移動互聯網和智能手機時代貢獻綿薄之力!能夠隨意轉載,但不得使用該文檔謀利。
另外:國士工做室已免費發佈原創教程《大話企業級Android開發》,請訪問國士工做室博客http://www.cnblogs.com/guoshiandroid/獲取教程。
·2007年末Google宣佈舉辦總獎金高達1000萬美圓的開發者大獎賽,鼓勵程序開發者在Android上寫出實用而又具備創意的應用程序;
·2009年5月27日,在Google的I/O開發者聚會上,Google發佈了總獎金接近2000萬美圓的第二次大獎賽的消息,開發者們開始了新一輪的較量;
Android是Google於2007年11月5日宣佈的基於Linux平臺的開源手機操做系統的名稱,該平臺由操做系統、中間件、用戶界面和應用軟件組成,號稱是首個爲移動終端打造的真正開放和完整的移動軟件。
Android一出生就被打上了富二代的胎記,不只僅是由於誕生於當今的網絡霸主Google,更主要還有一個空前強大和壯觀的開放手機聯盟OHA(Open Handset Alliance)提供全力的支持。OHA是什麼?OHA涵蓋了中國移動、T-Mobile、Sprint等移動運營商,包括HTC、Motolora、三星等手機制造商,有Google爲表明的手機軟件商,還有Inter、Nvidia爲標誌的底層硬件廠商和Astonishing Tribe等商業運做公司,該組織聲稱組織的全部成員都會基於Android來開發新的手機業務。
可是,要成爲Android高手並非一件容易的事情。並非不少人想象的可以飛快的寫出幾行漂亮的代碼去解決一些困難的問題就是Android高手了。真正的Android高手須要考慮的問題遠遠不是寫些漂亮的代碼就足夠的。下面是成爲一名真正的Android高手必須掌握和遵循的一些準則:
1,學會懶惰
2,精通Android體系架構、MVC、常見的設計模式、控制反轉(IoC)
3,編寫可重用、可擴展、可維護、靈活性高的代碼
4,高效的編寫高效的代碼
5,學會至少一門服務器端開發技術
一:學會懶惰
沒搞錯吧?居然讓程序開發人員學會懶惰?程序開發人員多是世界上最爲忙碌的一類人啦!對,沒錯,學會懶惰!正由於程序開發人員忙碌,正由於程序開發人員可能會在客戶無限變化的需求之下沒日沒夜的加班,因此要學會懶惰,這樣,你就能夠把更多的時間浪費在美好的事物身上!
如何懶惰:
1,Don't Reinvent the Wheel(不要重複發明輪子)。
2,Inventing the Wheel(發明輪子)。
1,Don't Reinvent the Wheel(不要重複發明輪子)。
「輪子理論」,也即「不要重複發明輪子」,這是西方國家的一句諺語,原話是:Don't Reinvent the Wheel。「不要重複發明輪子 」意思是企業中任何一項工做實際上都有人作過,咱們所須要作的就是找到作過這件事情的人。拿到軟件領域中就是指有的項目或功能,別人已經作過,咱們須要用的時候,直接拿來用便可,而不要從新制造。
Android號稱是首個爲移動終端打造的真正開放和完整的移動軟件。Android發佈後不久Google公司就發佈了操做系統核心(Kernel)與部分驅動程序的源代碼,到目前位置除了Google Map等Google公司的核心組件沒有開放源代碼外,Android基本完成了徹底的開源,這就極大的促進了Android的普及和移植。受到Android開放行爲和開源精神的影響,在世界各地,有成千上萬的程序員喜歡和別人分享本身的聰明才智和本身編寫的代碼。你能夠在Google的Android討論組或者Google搜索引擎上搜索到不少優秀的程序代碼。這樣作並非鼓勵你們成天等着讓別人爲你編寫代碼,而是你能夠「站在偉人的肩膀上」,充分發揚「拿來主義」,聰明地應用別人的程序代碼能夠節省你大量的時間。
下面筆者爲你們介紹幾個通用的類,這些類來自筆者平日的收集,若是你能把它們加入到你本身的類庫中,早晚你會發現本身在進行Android開發的時候受益無窮:
1) 從輸入流中獲取數據並以字節數組返回,這種輸入流能夠來自Android本地也能夠來自網絡。
代碼
1
import
java.io.ByteArrayOutputStream;
2
3
import
java.io.InputStream;
4
5
6
7
public
class
StreamTool {
8
9
/**
10
11
* 從輸入流獲取數據
12
13
*
@param
inputStream
14
15
*
@return
16
17
*
@throws
Exception
18
19
*/
20
21
public
static
byte
[] readInputStream(InputStream inputStream)
throws
Exception {
22
23
byte
[] buffer
=
new
byte
[
1024
];
//
你能夠根據實際須要調整緩存大小
24
25
int
len
=
-
1
;
26
27
ByteArrayOutputStream outSteam
=
new
ByteArrayOutputStream();
28
29
while
( (len
=
inputStream.read(buffer))
!=
-
1
){
30
31
outSteam.write(buffer,
0
, len);
32
33
}
34
35
outSteam.close();
36
37
inputStream.close();
38
39
return
outSteam.toByteArray();
40
41
}
42
43
}
44
45
2) 經過Android客戶端上傳數據到服務器:能夠上傳簡單的表單,也能夠方便的上傳帶有附件的文件,此類遠遠比Android自身的HttpClient更高效、更易於使用:
代碼
import
java.io.DataOutputStream;
import
java.io.InputStream;
import
java.net.HttpURLConnection;
import
java.net.URL;
import
java.net.URLEncoder;
import
java.util.ArrayList;
import
java.util.List;
import
java.util.Map;
import
org.apache.http.HttpResponse;
import
org.apache.http.NameValuePair;
import
org.apache.http.client.HttpClient;
import
org.apache.http.client.entity.UrlEncodedFormEntity;
import
org.apache.http.client.methods.HttpPost;
import
org.apache.http.impl.client.DefaultHttpClient;
import
org.apache.http.message.BasicNameValuePair;
public
class
HttpRequester {
/**
* 直接經過HTTP協議提交數據到服務器,實現以下面表單提交功能:
* <FORM METHOD=POST ACTION="
http://192.168.0.200
:8080/ssi/fileload/test.do" enctype="multipart/form-data">
<INPUT TYPE="text" NAME="name">
<INPUT TYPE="text" NAME="id">
<input type="file" name="imagefile"/>
<input type="file" name="zip"/>
</FORM>
*
@param
actionUrl 上傳路徑(注:避免使用localhost或127.0.0.1這樣的路徑測試,由於它會指向手機模擬器,你可使用http://www.cnblogs.com/guoshiandroid或http://192.168.1.10:8080這樣的路徑測試)
*
@param
params 請求參數 key爲參數名,value爲參數值
*
@param
file 上傳文件
*/
public
static
String post(String actionUrl, Map
<
String, String
>
params, FormFile[] files) {
try
{
String BOUNDARY
=
"
---------7d4a6d158c9
"
;
//
數據分隔線
String MULTIPART_FORM_DATA
=
"
multipart/form-data
"
;
URL url
=
new
URL(actionUrl);
HttpURLConnection conn
=
(HttpURLConnection) url.openConnection();
conn.setConnectTimeout(
5
*
1000
);
conn.setDoInput(
true
);
//
容許輸入
conn.setDoOutput(
true
);
//
容許輸出
conn.setUseCaches(
false
);
//
不使用Cache
conn.setRequestMethod(
"
POST
"
);
conn.setRequestProperty(
"
Connection
"
,
"
Keep-Alive
"
);
conn.setRequestProperty(
"
Charset
"
,
"
UTF-8
"
);
conn.setRequestProperty(
"
Content-Type
"
, MULTIPART_FORM_DATA
+
"
; boundary=
"
+
BOUNDARY);
StringBuilder sb
=
new
StringBuilder();
for
(Map.Entry
<
String, String
>
entry : params.entrySet()) {
//
構建表單字段內容
sb.append(
"
--
"
);
sb.append(BOUNDARY);
sb.append(
"
\r\n
"
);
sb.append(
"
Content-Disposition: form-data; name=\
""
+ entry.getKey() +
"
\
"
\r\n\r\n
"
);
sb.append(entry.getValue());
sb.append(
"
\r\n
"
);
}
DataOutputStream outStream
=
new
DataOutputStream(conn.getOutputStream());
outStream.write(sb.toString().getBytes());
//
發送表單字段數據
for
(FormFile file : files){
//
發送文件數據
StringBuilder split
=
new
StringBuilder();
split.append(
"
--
"
);
split.append(BOUNDARY);
split.append(
"
\r\n
"
);
split.append(
"
Content-Disposition: form-data;name=\
""
+ file.getFormname()+
"
\
"
;filename=\
""
+ file.getFilname() +
"
\
"
\r\n
"
);
split.append(
"
Content-Type:
"
+
file.getContentType()
+
"
\r\n\r\n
"
);
outStream.write(split.toString().getBytes());
if
(file.getInStream()
!=
null
){
byte
[] buffer
=
new
byte
[
1024
];
int
len
=
0
;
while
((len
=
file.getInStream().read(buffer))
!=-
1
){
outStream.write(buffer,
0
, len);
}
file.getInStream().close();
}
else
{
outStream.write(file.getData(),
0
, file.getData().length);
}
outStream.write(
"
\r\n
"
.getBytes());
}
byte
[] end_data
=
(
"
--
"
+
BOUNDARY
+
"
--\r\n
"
).getBytes();
//
數據結束標誌
outStream.write(end_data);
outStream.flush();
int
cah
=
conn.getResponseCode();
if
(cah
!=
200
)
throw
new
RuntimeException(
"
請求url失敗
"
);
InputStream is
=
conn.getInputStream();
int
ch;
StringBuilder b
=
new
StringBuilder();
while
( (ch
=
is.read())
!=
-
1
){
b.append((
char
)ch);
}
outStream.close();
conn.disconnect();
return
b.toString();
}
catch
(Exception e) {
throw
new
RuntimeException(e);
}
}
/**
* 提交數據到服務器
*
@param
actionUrl 上傳路徑(注:避免使用localhost或127.0.0.1這樣的路徑測試,由於它會指向手機模擬器,你可使用http://www.cnblogs.com/guoshiandroid或http://192.168.1.10:8080這樣的路徑測試)
*
@param
params 請求參數 key爲參數名,value爲參數值
*
@param
file 上傳文件
*/
public
static
String post(String actionUrl, Map
<
String, String
>
params, FormFile file) {
return
post(actionUrl, params,
new
FormFile[]{file});
}
public
static
byte
[] postFromHttpClient(String path, Map
<
String, String
>
params, String encode)
throws
Exception{
List
<
NameValuePair
>
formparams
=
new
ArrayList
<
NameValuePair
>
();
//
用於存放請求參數
for
(Map.Entry
<
String, String
>
entry : params.entrySet()){
formparams.add(
new
BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity
=
new
UrlEncodedFormEntity(formparams,
"
UTF-8
"
);
HttpPost httppost
=
new
HttpPost(path);
httppost.setEntity(entity);
HttpClient httpclient
=
new
DefaultHttpClient();
//
看做是瀏覽器
HttpResponse response
=
httpclient.execute(httppost);
//
發送post請求
return
StreamTool.readInputStream(response.getEntity().getContent());
}
/**
* 發送請求
*
@param
path 請求路徑
*
@param
params 請求參數 key爲參數名稱 value爲參數值
*
@param
encode 請求參數的編碼
*/
public
static
byte
[] post(String path, Map
<
String, String
>
params, String encode)
throws
Exception{
//
String params = "method=save&name="+ URLEncoder.encode("國士工做室", "UTF-8")+ "&age=28&";
//
須要發送的參數
StringBuilder parambuilder
=
new
StringBuilder(
""
);
if
(params
!=
null
&&
!
params.isEmpty()){
for
(Map.Entry
<
String, String
>
entry : params.entrySet()){
parambuilder.append(entry.getKey()).append(
"
=
"
)
.append(URLEncoder.encode(entry.getValue(), encode)).append(
"
&
"
);
}
parambuilder.deleteCharAt(parambuilder.length()
-
1
);
}
byte
[] data
=
parambuilder.toString().getBytes();
URL url
=
new
URL(path);
HttpURLConnection conn
=
(HttpURLConnection)url.openConnection();
conn.setDoOutput(
true
);
//
容許對外發送請求參數
conn.setUseCaches(
false
);
//
不進行緩存
conn.setConnectTimeout(
5
*
1000
);
conn.setRequestMethod(
"
POST
"
);
//
下面設置http請求頭
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(
"
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(
"
Content-Type
"
,
"
application/x-www-form-urlencoded
"
);
conn.setRequestProperty(
"
Content-Length
"
, String.valueOf(data.length));
conn.setRequestProperty(
"
Connection
"
,
"
Keep-Alive
"
);
//
發送參數
DataOutputStream outStream
=
new
DataOutputStream(conn.getOutputStream());
outStream.write(data);
//
把參數發送出去
outStream.flush();
outStream.close();
if
(conn.getResponseCode()
==
200
){
return
StreamTool.readInputStream(conn.getInputStream());
}
return
null
;
}
}
2,Inventing the Wheel(發明輪子)。
發明輪子?不錯,發明輪子!咱們不只要發明輪子,更要成爲努力成爲世界上發明輪子的主導力量,惟有這樣,才能談的上中華名族軟件大業的真正強大。在Android,要發明輪子,就是咱們要主動的是解決一些世界上他人未解決的難題或者創造新的編程框架或者對Android進行深度的改造以適合本身的業務發展須要。Google發佈了Android後不久,中國移動便投入了大量的人力和物力,在Android的基礎上建立融入本身業務並開發、封裝了新的功能的和框架的OMS,這是Android中發明輪子的一個很是重要的例子。可能你會說,這發明輪子也太難了吧,別急,咱們慢慢來,開發一個框架特定領域的框架吧!你可能會一臉無辜的說,開發一個框架是說的那麼容易嗎?固然不是啦。可是也並不是不可能,首先,咱們分析一下框架的魅力的源泉,看看Spring、Struts等Java EE框架,在看看.NET框架,固然也能夠看看發展的如火如荼、層出不窮的PHP框架,她們的強大和魅力的源泉都在於:IoC(Inversion of Control)。
Don't call us, we'll call you(別找我,我會來找你的)。咱們下面就本身發明一個輪子的模型,實際展現一個框架最初核心的類,讓你一飽眼福:
1) 下面的類是文件下載類,支持文件的多線程斷點續傳,使用該類的便可安全、高效的下載任何類型的二進制文件:
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileOutputStream;
import
java.io.RandomAccessFile;
import
java.net.HttpURLConnection;
import
java.net.URL;
import
java.util.LinkedHashMap;
import
java.util.Map;
import
java.util.Properties;
import
java.util.UUID;
import
java.util.concurrent.ConcurrentHashMap;
import
java.util.regex.Matcher;
import
java.util.regex.Pattern;
import
cn.itcast.service.FileService;
import
android.content.Context;
import
android.util.Log;
/**
* 文件下載器
*/
public
class
FileDownloader {
private
Context context;
private
FileService fileService;
private
static
final
String TAG
=
"
FileDownloader
"
;
/*
已下載文件大小
*/
private
int
downloadSize
=
0
;
/*
原始文件大小
*/
private
int
fileSize
=
0
;
/*
線程數
*/
private
DownloadThread[] threads;
/*
下載路徑
*/
private
URL url;
/*
本地保存文件
*/
private
File saveFile;
/*
下載記錄文件
*/
private
File logFile;
/*
緩存各線程最後下載的位置
*/
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
FileDownloader(Context context, String downloadUrl, File fileSaveDir,
int
threadNum) {
try
{
this
.context
=
context;
this
.downloadUrl
=
downloadUrl;
fileService
=
new
FileService(context);
this
.url
=
new
URL(downloadUrl);
if
(
!
fileSaveDir.exists()) fileSaveDir.mkdirs();
this
.threads
=
new
DownloadThread[threadNum];
HttpURLConnection conn
=
(HttpURLConnection) url.openConnection();
conn.setConnectTimeout(
6
*
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(
"
1沒法獲知文件大小
"
);
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()
+
1
);
}
this
.block
=
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
)
-
(
this
.block
*
i);
}
print(
"
已經下載的長度
"
+
this
.downloadSize);
}
}
else
{
throw
new
RuntimeException(
"
2服務器響應錯誤
"
);
}
}
catch
(Exception e) {
print(e.toString());
throw
new
RuntimeException(
"
3鏈接不到下載路徑
"
);
}
}
/**
* 獲取文件名
*/
private
String getFileName(HttpURLConnection conn) {
String filename
=
this
.url.toString().substring(
this
.url.toString().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
=
Pattern.compile(
"
.*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(DownloadProgressListener listener)
throws
Exception{
try
{
if
(
this
.data.size()
!=
this
.threads.length){
this
.data.clear();
for
(
int
i
=
0
; i
<
this
.threads.length; i
++
) {
this
.data.put(i
+
1
,
this
.block
*
i);
}
}
for
(
int
i
=
0
; i
<
this
.threads.length; i
++
) {
int
downLength
=
this
.data.get(i
+
1
)
-
(
this
.block
*
i);
if
(downLength
<
this
.block
&&
this
.data.get(i
+
1
)
<
this
.fileSize){
//
該線程未完成下載時,繼續下載
RandomAccessFile randOut
=
new
RandomAccessFile(
this
.saveFile,
"
rw
"
);
if
(
this
.fileSize
>
0
) randOut.setLength(
this
.fileSize);
randOut.seek(
this
.data.get(i
+
1
));
this
.threads[i]
=
new
DownloadThread(
this
,
this
.url, randOut,
this
.block,
this
.data.get(i
+
1
), i
+
1
);
this
.threads[i].setPriority(
7
);
this
.threads[i].start();
}
else
{
this
.threads[i]
=
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[i]
!=
null
&&
!
this
.threads[i].isFinish()) {
notFinish
=
true
;
//
下載沒有完成
if
(
this
.threads[i].getDownLength()
==
-
1
){
//
若是下載失敗,再從新下載
RandomAccessFile randOut
=
new
RandomAccessFile(
this
.saveFile,
"
rw
"
);
randOut.seek(
this
.data.get(i
+
1
));
this
.threads[i]
=
new
DownloadThread(
this
,
this
.url, randOut,
this
.block,
this
.data.get(i
+
1
), i
+
1
);
this
.threads[i].setPriority(
7
);
this
.threads[i].start();
}
}
}
if
(listener
!=
null
) listener.onDownloadSize(
this
.downloadSize);
}
fileService.delete(
this
.downloadUrl);
}
catch
(Exception e) {
print(e.toString());
throw
new
Exception(
"
下載失敗
"
);
}
return
this
.downloadSize;
}
/**
* 獲取Http響應頭字段
*
@param
http
*
@return
*