转自 http://www.2cto.com/kf/201501/368943.html
大家知道Google支持和发布的Android移动操作系统,主要是为了使其迅速占领移动互联网的市场份额,所谓移动互联网当然也是互联网了,凡是涉及互联网的任何软件任何程序都少不了联网模块的开发,诚然Android联网开发也是我们开发中至关重要的一部分,那么Android是怎么样进行联网操作的呢?这篇博客就简单的介绍一下Android常用的联网方式,包括JDK支持的HttpUrlConnection,Apache支持的HttpClient,以及开源的一些联网框架(譬如AsyncHttpClient)的介绍。本篇博客只讲实现过程和方式,不讲解原理,否则原理用文字很难以讲清,其实我们知道怎么去用,就可以解决一些基本开发需要了。
绝大多数的Android应用联网都是基于Http协议的,也有很少是基于Socket的,我们这里主要讲解基于Http协议的联网方式。讲解实例是建立在一个模拟的登录小模块中进行,登录请求数据仅仅只有username和password两个简单字段。
HttpUrlConnection
HttpUrlConnection是JDK里提供的联网API,我们知道Android SDK是基于Java的,所以当然优先考虑HttpUrlConnection这种最原始最基本的API,其实大多数开源的联网框架基本上也是基于JDK的HttpUrlConnection进行的封装罢了,掌握HttpUrlConnection需要以下几个步骤:1将访问的路径转换成URL。
1
|
URL url =
new
URL(path);
|
2,通过URL获取连接。
1
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
3,设置请求方式。
1
|
conn.setRequestMethod(GET);
|
4,设置连接超时时间。
1
|
conn.setConnectTimeout(
5000
);
|
5,设置请求头的信息。
1
|
conn.setRequestProperty(User-Agent, Mozilla/
5.0
(compatible; MSIE
9.0
; Windows NT
6.1
; Trident/
5.0
));
|
6,获取响应码
1
|
int
code = conn.getResponseCode();
|
7,针对不同的响应码,做不同的操作
7.1,请求码200,表明请求成功,获取返回内容的输入流
1
|
InputStream is = conn.getInputStream();
|
7.2,将输入流转换成字符串信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public
class
StreamTools {
/**
* 将输入流转换成字符串
*
* @param is
* 从网络获取的输入流
* @return
*/
public
static
String streamToString(InputStream is) {
try
{
ByteArrayOutputStream baos =
new
ByteArrayOutputStream();
byte
[] buffer =
new
byte
[
1024
];
int
len =
0
;
while
((len = is.read(buffer)) != -
1
) {
baos.write(buffer,
0
, len);
}
baos.close();
is.close();
byte
[] byteArray = baos.toByteArray();
return
new
String(byteArray);
}
catch
(Exception e) {
Log.e(tag, e.toString());
return
null
;
}
}
}
|
7.3,若返回值400,则是返回网络异常,做出响应的处理。
HttpUrlConnection发送GET请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/**
* 通过HttpUrlConnection发送GET请求
*
* @param username
* @param password
* @return
*/
public
static
String loginByGet(String username, String password) {
String path = http:
//192.168.0.107:8080/WebTest/LoginServerlet?username= + username + &password= + password;
try
{
URL url =
new
URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(
5000
);
conn.setRequestMethod(GET);
int
code = conn.getResponseCode();
if
(code ==
200
) {
InputStream is = conn.getInputStream();
// 字节流转换成字符串
return
StreamTools.streamToString(is);
}
else
{
return
网络访问失败;
}
}
catch
(Exception e) {
e.printStackTrace();
return
网络访问失败;
}
}
|
HttpUrlConnection发送POST请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/**
* 通过HttpUrlConnection发送POST请求
*
* @param username
* @param password
* @return
*/
public
static
String loginByPost(String username, String password) {
String path = http:
//192.168.0.107:8080/WebTest/LoginServerlet;
try
{
URL url =
new
URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(
5000
);
conn.setRequestMethod(POST);
conn.setRequestProperty(Content-Type, application/x-www-form-urlencoded);
String data = username= + username + &password= + password;
conn.setRequestProperty(Content-Length, data.length() + );
// POST方式,其实就是浏览器把数据写给服务器
conn.setDoOutput(
true
);
// 设置可输出流
OutputStream os = conn.getOutputStream();
// 获取输出流
os.write(data.getBytes());
// 将数据写给服务器
int
code = conn.getResponseCode();
if
(code ==
200
) {
InputStream is = conn.getInputStream();
return
StreamTools.streamToString(is);
}
else
{
return
网络访问失败;
}
}
catch
(Exception e) {
e.printStackTrace();
return
网络访问失败;
}
}
|
HttpClient
HttpClient是开源组织Apache提供的Java请求网络框架,其最早是为了方便Java服务器开发而诞生的,是对JDK中的HttpUrlConnection各API进行了封装和简化,提高了性能并且降低了调用API的繁琐,Android因此也引进了这个联网框架,我们再不需要导入任何jar或者类库就可以直接使用,值得注意的是Android官方已经宣布不建议使用HttpClient了,我们再开发的时候尽量少用吧,但是用了也无妨!HttpClient发送GET请求
1, 创建HttpClient对象
2,创建HttpGet对象,指定请求地址(带参数)
3,使用HttpClient的execute(),方法执行HttpGet请求,得到HttpResponse对象
4,调用HttpResponse的getStatusLine().getStatusCode()方法得到响应码
5,调用的HttpResponse的getEntity().getContent()得到输入流,获取服务端写回的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/**
* 通过HttpClient发送GET请求
*
* @param username
* @param password
* @return
*/
public
static
String loginByHttpClientGet(String username, String password) {
String path = http:
//192.168.0.107:8080/WebTest/LoginServerlet?username=
+ username + &password= + password;
HttpClient client =
new
DefaultHttpClient();
// 开启网络访问客户端
HttpGet httpGet =
new
HttpGet(path);
// 包装一个GET请求
try
{
HttpResponse response = client.execute(httpGet);
// 客户端执行请求
int
code = response.getStatusLine().getStatusCode();
// 获取响应码
if
(code ==
200
) {
InputStream is = response.getEntity().getContent();
// 获取实体内容
String result = StreamTools.streamToString(is);
// 字节流转字符串
return
result;
}
else
{
return
网络访问失败;
}
}
catch
(Exception e) {
e.printStackTrace();
return
网络访问失败;
}
}
|
HttpClient发送POST请求
1,创建HttpClient对象
2,创建HttpPost对象,指定请求地址
3,创建List,用来装载参数
4,调用HttpPost对象的setEntity()方法,装入一个UrlEncodedFormEntity对象,携带之前封装好的参数
5,使用HttpClient的execute()方法执行HttpPost请求,得到HttpResponse对象
6, 调用HttpResponse的getStatusLine().getStatusCode()方法得到响应码
7, 调用的HttpResponse的getEntity().getContent()得到输入流,获取服务端写回的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/**
* 通过HttpClient发送POST请求
*
* @param username
* @param password
* @return
*/
public
static
String loginByHttpClientPOST(String username, String password) {
String path = http:
//192.168.0.107:8080/WebTest/LoginServerlet;
try
{
HttpClient client =
new
DefaultHttpClient();
// 建立一个客户端
HttpPost httpPost =
new
HttpPost(path);
// 包装POST请求
// 设置发送的实体参数
List<namevaluepair> parameters =
new
ArrayList<namevaluepair>();
parameters.add(
new
BasicNameValuePair(username, username));
parameters.add(
new
BasicNameValuePair(password, password));
httpPost.setEntity(
new
UrlEncodedFormEntity(parameters, UTF-
8
));
HttpResponse response = client.execute(httpPost);
// 执行POST请求
int
code = response.getStatusLine().getStatusCode();
if
(code ==
200
) {
InputStream is = response.getEntity().getContent();
String result = StreamTools.streamToString(is);
return
result;
}
else
{
return
网络访问失败;
}
}
catch
(Exception e) {
e.printStackTrace();
return
访问网络失败;
}
}</namevaluepair></namevaluepair>
|
其他开源联网框架
AsyncHttpClient
除了上述Android官方推荐的联网框架以外,在开源世界里关于联网框架真是太多太多了,例如afinal,xutils等等,都是一些开源大牛自己封装的联网框架,并且在GitHub开源社区中可以 下载 到,其实类似的开源联网框架基本上也是基于HttpUrlConnection的进一步封装,大大提高了性能,同时更加简化了使用方法,这里使用AsyncHttpClient作为案例,其他的联网框架大家可以去网上找,下载使用试试便可。 AsyncHttpClient是一个非常优秀的联网框架,不仅支持所有Http请求的方式,而且还支持文件的上传和下载,要知道用HttpUrlConnection写一个文件上传和下载健全功能是很需要花费一定时间和精力的,因为请求头实在是太多了,稍有不慎就会写错。但是AsyncHttpClient已经封装好了这些“麻烦”,我们只需要下载到AsyncHttpClient的jar包或者 源码 导入项目中,Http,上传,下载等等,只需要几个简单的api即可搞定。 AsyncHttpClient的GitHub主页:https://github.com/AsyncHttpClient/async-http-client/AsyncHttpClient发送GET请求
1,将下载好的源码拷贝到src目录下
2,创建一个AsyncHttpClient的对象
3,调用该类的get方法发送GET请求,传入请求资源地址URL,创建AsyncHttpResponseHandler对象
4,重写AsyncHttpResponseHandler下的两个方法,onSuccess和onFailure方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
/**
* 通过AsyncHttpClient发送GET请求
*/
public
void
loginByAsyncHttpGet() {
String path = http:
//192.168.0.107:8080/WebTest/LoginServerlet?username=zhangsan&password=123;
AsyncHttpClient client =
new
AsyncHttpClient();
client.get(path,
new
AsyncHttpResponseHandler() {
@Override
public
void
onFailure(
int
arg0, Header[] arg1,
byte
[] arg2,
Throwable arg3) {
// TODO Auto-generated method stub
Log.i(TAG, 请求失败: +
new
String(arg2));
}
@Override
public
void
onSuccess(
int
arg0, Header[] arg1,
byte
[] arg2) {
// TODO Auto-generated method stub
Log.i(TAG, 请求成功: +
new
String(arg2));
}
});
}
|
AsyncHttpClient发送POST请求
1,将下载好的源码拷贝到src目录下
2,创建一个AsyncHttpClient的对象
3,创建请求参数,RequestParams对象
4,调用该类的post方法发POST,传入请求资源地址URL,请求参数RequestParams,创建AsyncHttpResponseHandler对象
5,重写AsyncHttpResponseHandler下的两个方法,onSuccess和onFailure方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* 通过AsyncHttpClient发送POST请求
*/
public
void
loginByAsyncHttpPost() {
String path = http:
//192.168.0.107:8080/WebTest/LoginServerlet;
AsyncHttpClient client =
new
AsyncHttpClient();
RequestParams params =
new
RequestParams();
params.put(username, zhangsan);
params.put(password,
123
);
client.post(path, params,
new
AsyncHttpResponseHandler() {
@Override
public
void
onFailure(
int
arg0, Header[] arg1,
byte
[] arg2,
Throwable arg3) {
// TODO Auto-generated method stub
Log.i(TAG, 请求失败: +
new
String(arg2));
}
@Override
public
void
onSuccess(
int
arg0, Header[] arg1,
byte
[] arg2) {
// TODO Auto-generated method stub
Log.i(TAG, 请求成功: +
new
String(arg2));
}
});
}
|
AsyncHttpClient上传文件
1,将下载好的源码拷贝到src目录下
2,创建一个AsyncHttpClient的对象
3,创建请求参数,RequestParams对象,请求参数仅仅包含文件对象即可,例如:
1
|
params.put(profile_picture,
new
File(/sdcard/pictures/pic.jpg));
|
4,调用该类的post方法发POST,传入请求资源地址URL,请求参数RequestParams,创建AsyncHttpResponseHandler对象
5,重写AsyncHttpResponseHandler下的两个方法,onSuccess和onFailure方法
判断网络连接状态
很多时候对于手机或者平板电脑这样的手持设备,我们是不知道它们的网络连接状态的,在联网的时候我们必须得保证设备的网路是否正常,是否可以连接上互联网,或者我们在进行大量数据上传或者下载,例如下载网路视频,看网路电视等等,我们必须得为用户省钱,这样大数据的传输显然是不能使用用户昂贵的数据流量的,而是判断当前网络是不是在wifi下,使用WiFi来进行大数据的传输,会给用户更好的体验,那么下面这个工具类就是用来判断设备网络连接状态的,不仅判断了当前设置手机网络下还是WiFi环境下,而且如果手机网络下还需要设置运营商的代理IP和端口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
/**
* 判断网络状态的工具类
*
*/
public
class
NetworkUtil {
/* 代码IP */
private
static
String PROXY_IP =
null
;
/* 代理端口 */
private
static
int
PROXY_PORT =
0
;
/**
* 判断当前是否有网络连接
*
* @param context
* @return
*/
public
static
boolean
isNetwork(Context context) {
boolean
network = isWifi(context);
boolean
mobilework = isMobile(context);
if
(!network && !mobilework) {
// 无网络连接
Log.i(NetworkUtil, 无网路链接!);
return
false
;
}
else
if
(network ==
true
&& mobilework ==
false
) {
// wifi连接
Log.i(NetworkUtil, wifi连接!);
}
else
{
// 网络连接
Log.i(NetworkUtil, 手机网路连接,读取代理信息!);
readProxy(context);
// 读取代理信息
return
true
;
}
return
true
;
}
/**
* 读取网络代理
*
* @param context
*/
private
static
void
readProxy(Context context) {
Uri uri = Uri.parse(content:
//telephony/carriers/preferapn);
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(uri,
null
,
null
,
null
,
null
);
if
(cursor !=
null
&& cursor.moveToFirst()) {
PROXY_IP = cursor.getString(cursor.getColumnIndex(proxy));
PROXY_PORT = cursor.getInt(cursor.getColumnIndex(port));
}
cursor.close();
}
/**
* 判断当前网络是否是wifi局域网
*
* @param context
* @return
*/
public
static
boolean
isWifi(Context context) {
ConnectivityManager manager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager
.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if
(info !=
null
) {
return
info.isConnected();
// 返回网络连接状态
}
return
false
;
}
/**
* 判断当前网络是否是手机网络
*
* @param context
* @return
*/
public
static
boolean
isMobile(Context context) {
ConnectivityManager manager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if
(info !=
null
) {
return
info.isConnected();
// 返回网络连接状态
}
return
false
;
}
}
|