在Android上发送Http请求的方式一般有两种,HttpURLConnection和HttpClient,但是HttpClient在android5.1以后好像被废弃了,大家可以在网上搜索一下相关的资讯。
今天来写一下HttpURLConnection的使用实例,再做一个它的简单讲解。
我们尝试请求一下www.baidu.com的首页,然后把返回的数据放到一个TextView 中去显示出来。
视图上的布局就不在这里贴代码了,就一个按钮,一个TextView
看一下MainActivity中的代码吧
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final int SHOW_RESPONSE = 0;
private Button sendRequest;
private TextView responseText;
private TextView result;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case SHOW_RESPONSE:
String response = (String) msg.obj;
public static final int SHOW_RESPONSE = 0;
private Button sendRequest;
private TextView responseText;
private TextView result;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case SHOW_RESPONSE:
String response = (String) msg.obj;
// parseXMLWithPull(response);
// parseXMLWithSAX(response);
responseText.setText(response);
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendRequest = (Button) findViewById(R.id.send_request);
responseText = (TextView) findViewById(R.id.response);
result = (TextView) findViewById(R.id.result);
sendRequest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.send_request:
sendRequestWithHttpURLConnection();
break;
default:
break;
}
}
private void sendRequestWithHttpURLConnection(){
//开启线程来发送网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try{
URL url = new URL("http://192.168.242.1:8080/get_data.xml");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
InputStream in = connection.getInputStream();//这条代码执行时是真正进行了请求的发送,之后再设置http头部内容已经无效了。
//下面对获取到的输入流进行读取
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null){
response.append(line);
}
Message message = new Message();
message.what = SHOW_RESPONSE;
message.obj = response.toString();
handler.sendMessage(message);
}catch (Exception e){
e.printStackTrace();
}
finally {
if (connection != null){
connection.disconnect();
}
}
}
}).start();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sendRequest = (Button) findViewById(R.id.send_request);
responseText = (TextView) findViewById(R.id.response);
result = (TextView) findViewById(R.id.result);
sendRequest.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.send_request:
sendRequestWithHttpURLConnection();
break;
default:
break;
}
}
private void sendRequestWithHttpURLConnection(){
//开启线程来发送网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try{
URL url = new URL("http://192.168.242.1:8080/get_data.xml");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
InputStream in = connection.getInputStream();//这条代码执行时是真正进行了请求的发送,之后再设置http头部内容已经无效了。
//下面对获取到的输入流进行读取
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null){
response.append(line);
}
Message message = new Message();
message.what = SHOW_RESPONSE;
message.obj = response.toString();
handler.sendMessage(message);
}catch (Exception e){
e.printStackTrace();
}
finally {
if (connection != null){
connection.disconnect();
}
}
}
}).start();
}
}
别忘记UI操作需要在主线程中执行,所以还是需要用到线程间通信的方式,记得回顾一下之前讲过的内容,一种是Handle和Message的通信方式,还有一种AsyncTask异步执行的方式。
以上就是HttpURLConnection的一个简单使用,下面来对它进行讲解。
首先需要获取到HttpURLConnection的实例,一般只需new出一个URL对象,并传入目标网络的地址,然后调用一下openConnection()方法即可,如下:
URL url = new URL("http://www.baidu.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
得到了HttpURLConnection对象的实例后,我们可以设置一下http请求所使用的方法。常用的方法主要有2个,GET和POST。关于这两个方法的区别可以在网上查一些资料。
然后我们就需要设置一下http报文的头部,都是一些自定的参数设置
connection.setConnectTimeout("5000"); //设置请求超时时间为5s
connection.setReadTimeout("5000"); //设置读取超时时间为5s
// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在
// http正文内,因此需要设为true, 默认情况下是false;
httpUrlConnection.setDoOutput(true);
// 设置是否从httpUrlConnection读入,默认情况下是true;
httpUrlConnection.setDoInput(true);
// Post 请求不能使用缓存
httpUrlConnection.setUseCaches(false);
// 设定传送的内容类型是可序列化的java对象
// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
httpUrlConnection.setRequestProperty("Content-type", "application/x-java-serialized-object");
// 设定请求的方法为"POST",默认是GET
httpUrlConnection.setRequestMethod("POST");
// 连接,从上述第2条中url.openConnection()至此的配置必须要在connect之前完成,
httpUrlConnection.connect();
之后再调用getInputStream()方法就可以获取到服务器返回的输入流了,剩下的任务就是对输入流进行读取,
InputStream in = connection.getInputStream();
最后可以调用disconnect()方法将这个http连接关闭掉
connection.disconnect();
4:> HttpURLConnection连接问题:
// 此处getOutputStream会隐含的进行connect(即:如同调用上面的connect()方法,
// 所以在开发中不调用上述的connect()也可以)。
OutputStream outStrm = httpUrlConnection.getOutputStream();
5:> HttpURLConnection写数据与发送数据问题:
//
现在通过输出流对象构建对象输出流对象,以实现输出可序列化的对象。
ObjectOutputStream objOutputStrm
=
new ObjectOutputStream(outStrm);
//
向对象输出流写出数据,这些数据将存到内存缓冲区中
objOutputStrm.writeObject(
new
String(
"
我是测试数据
"));
//
刷新对象输出流,将任何字节都写入潜在的流中(些处为ObjectOutputStream)
objOutputStm.flush();
// 关闭流对象。此时,不能再向对象输出流写入任何数据,先前写入的数据存在于内存缓冲区中,
//
在调用下边的getInputStream()函数时才把准备好的http请求正式发送到服务器
objOutputStm.close();
// 调用HttpURLConnection连接对象的getInputStream()函数,
//
将内存缓冲区中封装好的完整的HTTP请求电文发送到服务端。
InputStream inStrm
=
httpConn.getInputStream();
// <===注意,实际发送请求的代码段就在这里
// 上边的httpConn.getInputStream()方法已调用,本次HTTP请求已结束,下边向对象输出流的输出已无意义,
// 既使对象输出流没有调用close()方法,下边的操作也不会向对象输出流写入任何数据.
// 因此,要重新发送数据时需要重新创建连接、重新设参数、重新创建流对象、重新写数据、
//
重新发送数据(至于是否不用重新这些操作需要再研究)
objOutputStm.writeObject(
new
String(
""));
httpConn.getInputStream();
总结:
a:) HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。
无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。
b:) 在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重,
对connection对象的一切配置(那一堆set函
数)
都必须要在connect()函数执行之前完成。而对outputStream的写操作,又必须要在inputStream的读操作之前。
这些顺序实际上是由http请求的格式决定的。
如果inputStream读操作在outputStream的写操作之前,会抛出例外:
java.net.ProtocolException: Cannot write output after reading input.......
c:) http请求实际上由两部分组成,
c:) http请求实际上由两部分组成,
一个是http头,所有关于此次http请求的配置都在http头里面定义,
一个是正文content。
connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前,
就必须把所有的配置准备好。
d:) 在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的,
实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,
而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。
至此,http请求的东西已经全部准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求
正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http
请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数
之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)
实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,
而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。
至此,http请求的东西已经全部准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求
正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http
请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数
之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)
都是没有意义的了,执行这些操作会导致异常的发生。