声明:在保证本文完整的状况下可自由转载!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
*