疯狂安卓实训 第13.2.2讲 使用HttpURLConnection访问网络资源

第13.2.2讲 使用HttpURLConnection访问网络资源

1 HttpURLConnection简介

1.1 背景

(1.1.1)URL因为其网络通信的基本设置功能过于薄弱,很少使用;

(1.1.2)URLConnect在URL的基础上,进一步封装了网络通讯控制(例如超时)、区分了POST和GET,但是其对Response的解析支持过于薄弱,二次开发工作量大;

(1.1.3)在URLConnect的基础上,需要再进一步封装了,于是就出现了HttpURLConnect;



1.2 HttpURLConnect的新增内容

HttpURLConnectURL是URLConnectURL的一个子类,具有父类的基本属性特征;新增特色部分主要如下: (1.2.1)public Int getResponseCode():获取服务器的响应代码;发时根据响应码来判断后续内容的正确如否;

(1.2.2)public String getResponseMessage():获取服务器的响应消息;

(1.2.3)public Int getContentLength():获得内容的长度;

(1.2.4)public void setRequestMethod(String method):设置发送请求的的方法,参数method的取值为:“POST”或“GET”;

(1.2.5)public String getRequestMethod():获取发送请求的方法。

(1.2.6)public void disconnect():关闭当前的连接。




2 .HttpURLConnection

2.1 构造

(2.1.1)HttpURLConnection继续是一个抽象类,不能直接用new来实例化;

(2.1.2)URL的openConnection()方法将返回一个URLConnection对象,需要人为强制转换为HttpURLConnection类型,该对象表示应用程序和URL之间的通信连接;



2.2 通讯

HttpURLConnection的通讯区继续分GET模式和POST两种模式,每种模式的使用步骤都不相同; 2.2 get模式的 使用步骤

(2.2.1)确定URL的地址,参数组,构建URL。

(2.2.2)通过URL对象的openConnection()方法来创建HttpURLConnection对象。

(2.2.3)设置HttpURLConnection对象的常用的头字段内容和扩展头字段内容,例如超时、缓存、长连接等;

(2.2.4)取消URLConnection的connect()方法的执行,改为检查常用头字段设置中是否完成,和conn.setRequestMethod("GET")的GET模式设定;问:怎么此流程中貌似没有提交函数或者提交的触发函数呢?


(2.2.5)然后进入接收阶段,读取conn.getResponseCode()的返回值是否等于200;


int code=conn.getResponseCode();
if(code==HttpURLConnection.HTTP_OK){
     ...
  }


(2.2.6)不等于200,则通过conn.getResponseMessage()读取报错信息;

(2.2.7)等于200则表示OK,读者可以根据 conn.getResponseMessage()、conn.getHeaderFields()、conn.getInputStream()按需解析处理;

(2.2.8)处理完成后,建议读者执行conn.disconnect(),释放当前的网络连接资源;



2.3 post 使用步骤

(2.3.1)确定URL的地址,参数组,构建URL。

(2.3.2)通过URL对象的openConnection()方法来创建HttpURLConnection对象。

(2.3.3)设置URLConnection对象的常用的头字段内容和扩展头字段内容,例如超时、缓存、长连接等。

(2.3.4)查常用头字段设置中是否完成和conn.setRequestMethod("POST")的POST模式设定;

(2.3.4)设置HttpURLConnection的输入流和输出流为可用,只有设置启用后才能获取其对应的流。


  //代码片段
  //设置URLConnection对象在发送POST请求时,连接可读入输入信息。
  conn.setDoInput(true)
  //设置URLConnection对象在发送POST请求时,连接可以输出信息。
  conn.setDoOutput(true);
  

(2.3.5通过getOutputStream()获得输出流对象,进而发送请求参数;

  //生成一个字符打印流
  os = new PrintWriter(conn.getOutputStream());
  // 发送请求参数
  os.print(parms);
  // flush输出流的缓冲
  os.flush(); 
 

(2.3.6)然后进入接收阶段,读取conn.getResponseCode()的返回值是否等于200;

(2.3.6)不等于200,则通过conn.getResponseMessage()读取报错信息;

(2.3.7)等于200则表示OK,读者可以根据 conn.getResponseMessage()、conn.getHeaderFields()、conn.getInputStream()按需解析处理;

(2.3.8)处理完成后,建议读者执行conn.disconnect(),释放当前的网络连接资源;



2.4. GET和POS步骤比较
步骤GETPOST
URL连接串主地址串+?+参数串主地址串
打开连接(HttpURLConnection)
url.openConnection()
(HttpURLConnection)
url.openConnection()
设置头域设置主头域+扩展头域设置主头域+扩展头域
检查请求方式setRequestMethod("GET")setRequestMethod("POST")
检查头域--必须启动输入流和输出流
输出参数--通过输出流格式输出参数串
连接服务器--(跟URLConnect的比较)--
解析响应码getResponseCode()
getResponseMessage()
getResponseCode()、
getResponseMessage()
解析头域getHeaderFields()getHeaderFields()
解析输入流getInputStream()getInputStream()
释放资源释放流资源、网络连接资源释放流资源、网络连接资源
3. 案例实训

演示(Fragment版)



3.1 需求 

需求1

在MainActivity部署一个输入框用于输入网址的主地址、一个输入框用于输入网址后面的参数串;

需求2

在MainActivity内部署3个按钮,一个用于get模式的测试、一个用于POST模式的测试、一个用于恢复默认的网址便于测试者不知道主地址和参数;

需求3

在MainActivity内部署1个只读的文本编辑框(因为文本编辑框具有滚动条),用于显示基本的头字段域内容和ResponseMessage的内容;

需求4

输入不同的网址和网址后缀的参数串,分别点击GET模式和POST模式的按钮,观察返回结果的变化;


3.2 步骤1 准备主布局、Demo13020201Fragment类、默认的网址

内容省略 3.3 步骤2 准备Button的事件


   @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView= inflater.inflate(R.layout.fragment_demo13020201,
container,false);
initViewInRootView(rootView);
return rootView;
}

/***
* 初始化Fragment内部的组件
*/
private void initViewInRootView(View rootView){
       //找到第1组按钮
mButton1=(Button)rootView.findViewById(R.id.button1);
mButton2=(Button)rootView.findViewById(R.id.button2);
mButton3=(Button)rootView.findViewById(R.id.button3);
//URL主地址和参数输入框
mEditText1=(EditText)rootView.findViewById(R.id.editText1);
mEditText2=(EditText)rootView.findViewById(R.id.editText2);
//内容提示框
mTextView=(TextView)rootView.findViewById(R.id.textView1);
mEditText3=(EditText)rootView.findViewById(R.id.editText3);
       //设置按钮的点击事件侦听器
mButton1.setOnClickListener(mButtonOnClickListener);
mButton2.setOnClickListener(mButtonOnClickListener);
mButton3.setOnClickListener(mButtonOnClickListener);
}



//按钮的点击事件侦听器
private View.OnClickListener mButtonOnClickListener=new View.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.button1:
demoByHttpGet();
break;
case R.id.button2:
demoByHttpPost();
break;
case R.id.button3:
setDefaultURL();
break;
}
}
};


3.4 步骤3 准备处理demoByHttpGet函数的处理内容 

(3.4.1)生成一个匿名线程,重写run()。 

(3.4.2)根据输入框的主地址和参数合并成并生成URL。

(3.4.3)通过 url.openConnection()获取一个连接,强制转换成HttpURLConnection后放到变量conn中。

(3.4.4)设置conn的设置通用的请求属性和设置通用的扩展 请求属性。

(3.4.5)检查conn.setRequestMethod("GET");

(3.4.6) 读取conn.getResponseCode()的返回值,和gconn.etResponseMessage()的值;

(3.4.7) 获取getHeaderFields中的键值对用于显示;

(3.4.8)准备 Handler和对应的处理函数;

(3.4.9)根据ResponseCode的不同,发送不同Handler消息;

(3.4.10)处理流关闭善后工作;


//HttpGet的演示
private void demoByHttpGet(){
        //如果当前已经有线程在运行,则不要继续
if(mThreadIsRun)
return;
mThreadIsRun=true;
mTextView.setText("等待:demoByHttpGet()");
   //启动一个匿名线程下载图片
new Thread() {
public void run() {
InputStream is=null;
try {
//------生成连接
// 定义一个URL对象
String urlStr=mEditText1.getText().toString()+"?"+mEditText2.getText().toString();
URL url = new URL(urlStr);
// 打开和URL之间的连接,并把强制转换为HttpURLConnection
HttpURLConnection conn= (HttpURLConnection) url.openConnection();
//-----设置通用的请求属性
//连接可读入输入信息
//conn.setDoInput(true);
//设置不使用缓存。
conn.setUseCaches(false);
                    //设置连接网络超时时间,以毫秒为单位;
conn.setConnectTimeout(20*1000);
                    //设置流读的最长超时时间
conn.setReadTimeout(10 * 1000);
//-----设置通用的扩展  请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
//设置请求模式
conn.setRequestMethod("GET");
                    //---------处理服务器端的响应
int code=conn.getResponseCode();
mResultText="ResponseCode="+code+"\r\n"+conn.getResponseMessage()+"\r\n";
if(code==HttpURLConnection.HTTP_OK){
mResultText+="-------HeaderFields-------";
Map> map = conn.getHeaderFields();
//显示一下返回的头字段,大家可以学习一下都有哪些扩展属性
for (String key : map.keySet()) {
mResultText+= key + " --> " + map.get(key)+"\r\n";
}
// 发送消息、通知UI组件显示该内容
mImageViewHandler.sendEmptyMessage(0x123);
}else{
// 发送消息、通知UI组件显示该内容
mImageViewHandler.sendEmptyMessage(0x124);
}
}catch (Exception e){
mResultText="发生异常"+e.getMessage();
mImageViewHandler.sendEmptyMessage(0x124);
e.printStackTrace();
}finally {
try {
if(is !=null)
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//设置线程运行结束
mThreadIsRun=false;
}
}
}.start();
}



//添加HTTP完成后的Handler
Handler mImageViewHandler =new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if(msg.what == 0x123){
mThreadIsRun=false;
mTextView.setText("HTTP调用成功,返回如下:");
mEditText3.setText(mResultText);  
}
else if(msg.what == 0x124){
mThreadIsRun=false;
mTextView.setText("HTTP调用异常,原因如下:");
mEditText3.setText(mResultText);
}
super.handleMessage(msg);
}
};


3.5 步骤4 准备处理demoByPOST函数的处理内容 

(3.5.1)生成一个匿名线程,重写run()。 

(3.5.2)从输入框提取主网址,利用地址构造一个URL。

(3.5.3)通过 url.openConnection()获取一个连接,强制转换成HttpURLConnection后放到变量conn中。

(3.5.4)设置conn的设置通用的请求属性和设置通用的扩展 请求属性。

(3.5.5)检查conn.setRequestMethod("POST");

(3.5.6)检查通用头字段属性中的输入流和输出流是否启动;

(3.5.7)获取conn的输出流,并用输出流构建一个格式输出字符流读写器保存到变量os中;

(3.5.8)利用os输出URL的参数部分,并提交;

(3.5.9) 读取conn.getResponseCode()的返回值,和gconn.etResponseMessage()的值;

(3.5.10) 获取getHeaderFields中的键值对用于显示;

(3.5.11)根据ResponseCode的不同,发送不同Handler消息;

(3.5.12)处理流关闭善后工作;


//HttpPost的演示
private void demoByHttpPost(){
        //如果当前已经有线程在运行,则不要继续
if(mThreadIsRun)
return;
        //如果当前已经有线程在运行,则不要继续
if(mThreadIsRun)
return;
mThreadIsRun=true;
mTextView.setText("等待:demoByHttpGet()");
   //启动一个匿名线程下载图片
new Thread() {
public void run() {
InputStream is=null;
BufferedReader br=null;
PrintWriter os=null;
try {
//------生成连接
// 定义一个URL对象
String urlStr=mEditText1.getText().toString();
URL url = new URL(urlStr);
// 打开和URL之间的连接,并把强制转换为HttpURLConnection
HttpURLConnection conn= (HttpURLConnection) url.openConnection();
//-----设置通用的请求属性
//连接可读入输入信息
conn.setDoInput(true);
conn.setDoOutput(true);
//设置不使用缓存。
conn.setUseCaches(false);
                    //设置连接网络超时时间,以毫秒为单位;
conn.setConnectTimeout(20*1000);
                    //设置流读的最长超时时间
conn.setReadTimeout(10 * 1000);
//-----设置通用的扩展  请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
//设置请求模式
conn.setRequestMethod("POST");

//-----发送参数
// 获取URLConnection对象对应的输出流
os = new PrintWriter(conn.getOutputStream());
// 发送请求参数
String parmStr=mEditText2.getText().toString();
os.print(parmStr);
//flush输出流的缓冲
os.flush();

                    //---------处理服务器端的响应
int code=conn.getResponseCode();
mResultText="ResponseCode="+code+"\r\n"+conn.getResponseMessage()+"\r\n";
if(code==HttpURLConnection.HTTP_OK){
mResultText+="-------HeaderFields-------";
Map> map = conn.getHeaderFields();
//显示一下返回的头字段,大家可以学习一下都有哪些扩展属性
for (String key : map.keySet()) {
mResultText+= key + " --> " + map.get(key)+"\r\n";
}
// 发送消息、通知UI组件显示该内容
mImageViewHandler.sendEmptyMessage(0x123);
}else{
// 发送消息、通知UI组件显示该内容
mImageViewHandler.sendEmptyMessage(0x124);
}
}catch (Exception e){
mResultText="发生异常"+e.getMessage();
mImageViewHandler.sendEmptyMessage(0x124);
e.printStackTrace();
}finally {
try {
if(is !=null)
is.close();
if(os !=null)
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//设置线程运行结束
mThreadIsRun=false;
}
}
}.start();
}


3.6 步骤5 加入权限

关于主机服务器回应的输入流和编码,本例不继续测试,兴趣的同学自己参照上一节内容自己练习; 3.7 步骤6 加入权限 


    <!-- 互联网权限 --> 
    <uses-permission android:name="android.permission.INTERNET" />


3.8 步骤7测试 网络正常时OK,网络异常时能提示错误消息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值