疯狂安卓实训 第13.2.1讲 使用URL和URLConnection访问网络资源

第13.2.1讲 使用URL和URLConnection访问网络资源

1 URL

1.1 URL格式回顾

通常情况而言,URL可以由协议名、主机、端口和资源组成.
格式:protocol://host:[port]/path/[parameters] [?query], 例如:
补充:格式中:?query(查询):用于给动态网页传递参数,可有多个参数,用“&”符号隔开,每个参数的名和值用“=”符号隔开; 

1.2 类URL的构造方法

(1.2.1)public URL(String spec);

(1.2.2)public URL(String protocol,String host,String file);

(1.2.4)public URL(String protocol,String host,int port,String file);



1.3 类URL的主要成员函数

(1.3.1)InputStream openStream(),打开与此URL的连接,并返回一个用于读取该RUL资源的InputStream;


InputStream is = url.openStream();


(1.3.2)URLConnection openConnection(),返回一个URLConnection对象,表示所引用的远程对象的连接;为后续URLConnection和HttpURLConnection服务;


URLConnection conn = url.openConnection();




1.4 直接通信的步骤和局限性

(1.4.1) 使用步骤就三步,第一步构建一个URL;第二步打开一个输入流,然后读取流;第三步关闭输入流; 

(1.4.2)通过url.openStream()虽然能直接打开网络资源,由于没有个性化的网络超时等,除了演示和后台服务中使用外,在UI的子线程中很少使用; 

1.5 案例应用代码片段


//功能演示1:从网络上下载一幅图片,显示Activity的ImageView上;
//功能演示2:从网络上下载一幅图片,保存到私有文件区下;

public class URLTestActivity extends Activity
{
   //用于显示图片
ImageView mImageView;
//代表从网络下载得到的图片
Bitmap  mBitmap;
   //图片下载完成后通过mBitmapHandler通知URLTestActivity刷新界面
Handler mBitmapHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x123)
{
// 使用ImageView显示该图片
mImageView.setImageBitmap(mBitmap);
}
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mImageView = (ImageView) findViewById(R.id.urlImageView);
       //启动一个匿名线程下载图片
new Thread()
{
public void run()
{
try
{
// 定义一个URL对象
URL url = new URL(" http://img5.imgtn.bdimg.com/"+
"it/u=1806774939,1961872736&fm=21&gp=0.jpg");
                   //---------功能演示1  
// 打开该URL对应的资源的输入流
InputStream is = url.openStream();
// 从InputStream中解析出图片放到成员变量mBitmap中,
                   // 注意:此种方式应用比较普遍
mBitmap = BitmapFactory.decodeStream(is);
// 发送消息、通知UI组件显示该图片
handler.sendEmptyMessage(0x123);
is.close();

                   //---------功能演示2  
// 再次打开URL对应的资源的输入流
is = url.openStream();
// 打开手机文件对应的输出流
OutputStream os = openFileOutput("demo.png"
, MODE_WORLD_READABLE);
byte[] buff = new byte[1024];
int hasRead = 0;
// 将URL对应的资源下载到本地
while((hasRead = is.read(buff)) > 0)
{
os.write(buff, 0 , hasRead);
}
is.close();
os.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}.start();
}
};


2 .URLConnection

2.1 构造

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

(2.1.2)URL的openConnection()方法将返回一个URLConnection对象,该对象表示应用程序和URL之间的通信连接;



2.2 通讯

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

(2.2.1)确定URL的地址,参数组,构建URL。get方式的网址特征为:网址+连接符?+参数组;不同参数之间用 & 连接;参数跟值之间用=连接;例如:


String params = “userName=value1&loginPwd=value2& …”;
URL url = new URL(uri +"?"+ params);


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

(2.2.3)设置URLConnection对象的常用的头字段内容和扩展头字段内容,例如超时、缓存、长连接等(get模式不需要设置流的启用);

(2.2.4)通过URLConnection对象connect()方法建立和远程资源之间的实际连接即可,即执行方法connect()时内部就以pos协议方式执行发送。

(2.2.5)然后进入接收阶段,通过URLConnection对象的getHeaderFields()函数读返回的头信息,按需解析流内部内容;

(2.2.6)通过URLConnection对象的getInputStream()函数获取其输入流,读取输入流的内容;按需解析;



2.3 post 使用步骤

(2.3.1)确定URL的地址,参数组,构建URL。post方式的网址特征为:网址是网址,参数组是参数组;不同参数之间用 & 连接;参数跟值之间用=连接;例如:


String params = “userName=value1&loginPwd=value2& …”;
URL url = new URL(uri);

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

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

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


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

(2.3.5通过getOutputStream()获得输出流对象,进而发送请求参数;(post模式改connect为写参数);


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

(2.3.6)然后进入接收阶段,通过URLConnection对象的getHeaderFields()函数读返回的头信息,按需解析流内部内容;

(2.3.7)过URLConnection对象的getInputStream()函数获取其输入流,读取输入流的内容;按需解析;



2.4. GET和POS步骤比较
步骤GETPOST
URL连接串主地址串+?+参数串主地址串
打开连接openConnectionopenConnection
设置头域设置主头域+扩展头域设置主头域+扩展头域
检查头域--必须启动输入流和输出流
输出参数--通过输出流格式输出参数串
连接服务器connect()--
解析头域getHeaderFields()getHeaderFields()
解析输入流getInputStream()getInputStream()
释放资源释放流资源、网络连接资源释放流资源、网络连接资源
2.5. 相关字节字符流函数的主要方法

(2.5.1.) InputStream 字节输入流;用于从字节流中读字节数组;例如:


 ...
 // 打开该URL对应的资源的输入流
 InputStream is = url.openStream();
 byte[] buff = new byte[1024];
 int hasRead = 0;
 // 将URL对应的资源下载到本地
 while((hasRead = is.read(buff)) > 0) {
 ...
 }

(2.5.2.) BufferedReader 字符流阅读器;用于从字符流中读字符串;例如:


 ...
 URLConnection conn = url.openConnection(); 
 ...
 //注意重点1  利用conn的输入流生成一个字符流阅读器,
 BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
 //从字符阅读器中读字符串; 
 String line;
 //注意重点2
 while ((line = in.readLine()) != null){
result += "\n" + line;
 }
 ...


(2.5.3.)PrintWriter向文本输出流打印对象的格式化表示形式;例如:


 public testByPost(String urlStr,String... argStr) {
     URL readUrl = new URL(urlStr);
     // 打开和URL之间的连接 
     URLConnection conn = readUrl.openConnection();
     // 设置通用的请求属性 
     ...
  //注意重点1  把输出流转化为格式文本打印流
     PrintWriter out = new PrintWriter(conn.getOutputStream());
     //重新组织参数串
     String params="";
     for(String item : argStr){
     ...
     }
     //处理完后的格式应该是这样的 String params = “userName=value1&loginPwd=value2& …”; 
     ...
     // 发送请求参数
  out.print(params); 
  //注意重点2   flush输出流的缓冲
  out.flush();
     ...
     //处理返回数据 见上例代码  
     ... 




2.6. URLConnection常用的头字段内容

(2.6.1.)conn.setDoInput(boolean param):设置URLConnection对象在发送POST请求时,连接可读入输入信息。;

(2.6.2.)conn.setDoOutput(boolean param):设置URLConnection对象在发送POST请求时,连接可以输出信息。 如果设置为真,则认为是POST模式。

(2.6.3.)conn.setUseCaches(boolean param):设置使用缓存。

(2.6.4.)conn. setConnectTimeout(int msecond):设置连接网络超时时间,以毫秒为单位;

(2.6.5.)conn.setReadTimeout(10 * 1000); 设置流读的最长超时时间;

(2.6.6.)conn.setRequestMethod("POST"), 设置请求协议为POST或者GET;




2.7. URLConnection常用的扩展头字段内容

(2.7.1.)扩展头字段的函数原型: public void conn.setRequestProperty (String field,String newValue); 

(2.7.2.) conn.setRequestProperty(“accept”,”*/*”); //设置请求资源的类型为全部;

(2.7.2.) conn.setRequestProperty(“connection”,”Keep-Alive”);//设置连接保持长连接。

(2.7.3.)conn.setRequestProperty("Charsert", "UTF-8");置使字符集。

(2.7.4.) conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");设置协议包头识别字,可以是用户自定义内容;目前经常被自定义为用于识别苹果手机、安卓手机等;

(2.7.5.)conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA
+ ";boundary=" + BOUNDARY) 内容类型,一般在文件上传时需要设置本属性,其它的都不设置;




2.8. 如何查看头字段都有哪些内容

(2.8.1.)终端盒服务器端通信时,双方都是根据头字段的内容对后续的正文进行解析,了解都有哪些头字段成为必要; 

(2.8.2.) Map<String, List<String>> map = conn.getHeaderFields()获取头字段的HASHMAP,例子:


// 获取所有响应头字段
Map> map = conn.getHeaderFields();
//显示一下返回的头字段,大家可以学习一下都有哪些扩展属性
for (String key : map.keySet()) {
Log.d("GET", key + "--->" + map.get(key));
}
//如果返回类型是"text/html",进入对应的解析 
List type=map.get("Content-Type");
if(type != null && type.contains("text/html")){
  ...
}


(2.8.2.) URLConnection还提供了另外一种快捷存取的方法函数,常见的有:

(2.8.3.1) conn.getContentEncodeing:获取content-encoding相应头字段的值;
(2.8.3.2) conn.getContentLength:获取content-length相应头的长度;
(2.8.3.3) conn.getContentType:获取content-type相应的值; 



3. 案例实训

演示(Fragment版)



3.1 需求 

需求1

从百度图片上找到4副图片,把对应的完整网址记录到字符串数组中;

需求2

在MainActivity内部署3排按钮,每排各4个,后续操作时各对应一副图片;部署一个TextView用于显示操作提示;部署一个ImageView用于显示百度图片;

需求3

点击第一组按钮时,通过URL的输入流获取图片,存入Bitmap变量中,然后显示到ImageView上,同时修改提示;

需求4

点击第二组按钮时,通过URLConnectde get方式从输入流获取图片,存入Bitmap变量中,然后显示到ImageView上,同时修改提示;

需求5

点击第三组按钮时,通过URLConnectde POST方式从输入流获取图片,存入Bitmap变量中,然后显示到ImageView上,同时修改提示;



3.2 步骤1 准备主布局、Demo13020101Fragment类、百度图片


   //图片资源如下,其余内容省略    
String mUrl1[]=new String[]{
  };
  String mUrl2[]=new String[]{
     " http://image.baidu.com/detail/newindex?col=搞笑&tag=百思不得姐&pn=5&pid=11224252012&aid=11568319695&user_id=10086&setid=-1&sort=0&newsPn=&fr=&from=1",
    " http://image.baidu.com/detail/newindex?col=搞笑&tag=百思不得姐&pn=1&pid=11568319695&aid=11568319695&user_id=10086&setid=-1&sort=0&newsPn=&fr=&from=1",
    " http://image.baidu.com/detail/newindex?col=搞笑&tag=熊孩子&pn=17&pid=11736427002&aid=11736427002&user_id=10086&setid=-1&sort=0&newsPn=&fr=&from=1",
    " http://image.baidu.com/detail/newindex?col=搞笑&tag=全部&pn=10&pid=9857966033&aid=9857966033&user_id=10086&setid=-1&sort=0&newsPn=&fr=&from=1"
  };



3.3 步骤2 准备Button的事件


/***
* 初始化Fragment内部的组件
*/
    private void initViewInRootView(View rootView){
        //找到第1组按钮
mButton11=(Button)rootView.findViewById(R.id.button11);
mButton12=(Button)rootView.findViewById(R.id.button12);
mButton13=(Button)rootView.findViewById(R.id.button13);
mButton14=(Button)rootView.findViewById(R.id.button14);
        //找到第2组按钮
mButton21=(Button)rootView.findViewById(R.id.button21);
mButton22=(Button)rootView.findViewById(R.id.button22);
mButton23=(Button)rootView.findViewById(R.id.button23);
mButton24=(Button)rootView.findViewById(R.id.button24);
        //找到第3组按钮
mButton31=(Button)rootView.findViewById(R.id.button31);
mButton32=(Button)rootView.findViewById(R.id.button32);
mButton33=(Button)rootView.findViewById(R.id.button33);
mButton34=(Button)rootView.findViewById(R.id.button34);
        //找到提示和图片组件
mTextView=(TextView)rootView.findViewById(R.id.textView1);
mImageView=(ImageView)rootView.findViewById(R.id.imageView1);
        //设置按钮的点击事件侦听器
mButton11.setOnClickListener(mButtonOnClickListener);
mButton12.setOnClickListener(mButtonOnClickListener);
mButton13.setOnClickListener(mButtonOnClickListener);
mButton14.setOnClickListener(mButtonOnClickListener);
mButton21.setOnClickListener(mButtonOnClickListener);
mButton22.setOnClickListener(mButtonOnClickListener);
mButton23.setOnClickListener(mButtonOnClickListener);
mButton24.setOnClickListener(mButtonOnClickListener);
mButton31.setOnClickListener(mButtonOnClickListener);
mButton32.setOnClickListener(mButtonOnClickListener);
mButton33.setOnClickListener(mButtonOnClickListener);
mButton34.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.button11:        
               demoByURL(0);  
             break;
            case R.id.button12:
               demoByURL(1);
               break;
            case R.id.button13:
               demoByURL(2);
               break;
            case R.id.button14:
               demoByURL(3);
               break;
            case R.id.button21:
               demoByGET(0);
               break;
            case R.id.button22:
               demoByGET(1);
               break;
            case R.id.button23:
               demoByGET(2);
               break;
            case R.id.button24:
               demoByGET(3);
               break;
            case R.id.button31:
               demoByPOST(0);
               break;
            case R.id.button32:
               demoByPOST(1);
               break;
            case R.id.button33:
                demoByPOST(2);
                break;
           case R.id.button34:
              demoByPOST(3);  
              break;
            }
       }
    };


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

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

(3.4.2)根据传入的参数序号提取图片的网址,构造一个URL的实例 url。

(3.4.3)取url的输入流存入到 is中。

(3.4.4)利用BitmapFactory从is中读取Bitmap数据放到mBitmap中。

(3.4.5)在Fragment内生成一个Handler类型的成员变量 mImageViewHandler,并在其handleMessage方法中利用mBitmap刷新ImageView中的显示图片;

(3.4.6)继续在线程的run中利用mImageViewHandler发送一个图片下载成功的消息;

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


//URL的演示
private void demoByURL(final int buttonIndex){
        //如果当前已经有线程在运行,则不要继续
if(mThreadIsRun)
return;
mThreadIsRun=true;
mTextView.setText("等待:demoByURL("+buttonIndex+")");
   //启动一个匿名线程下载图片
new Thread() {
public void run() {
InputStream is=null;
try {
// 定义一个URL对象
URL url = new URL(mUrl1[buttonIndex]);
// 打开该URL对应的资源的输入流
is = url.openStream();
// 从InputStream中解析出图片放到成员变量mBitmap中,
               // 注意:此种方式应用比较普遍
mBitmap = BitmapFactory.decodeStream(is);
// 发送消息、通知UI组件显示该图片
mImageViewHandler.sendEmptyMessage(0x123);
}catch (Exception e){
e.printStackTrace();
}finally {
if(is !=null){
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//设置线程运行结束
mThreadIsRun=false;
}
}
}.start();
}


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

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

(3.5.2)根据传入的参数序号提取图片的网址,构造一个URL的实例 url。

(3.5.3)通过 url.openConnection()获取一个连接放到变量conn中。

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

(3.5.5)执行conn的connect建立实际连接;

(3.5.6) 获取所有响应头字段,显示一下头字段内容;

(3.5.7) 获取输入流,利用BitmapFactory从is中读取Bitmap数据放到mBitmap中;

(3.5.8)继续在线程的run中利用mImageViewHandler发送一个图片下载成功的消息;

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


//GET的演示
private void demoByGET(final int buttonIndex){
       //如果当前已经有线程在运行,则不要继续
if(mThreadIsRun)
return;
mThreadIsRun=true;
mTextView.setText("等待:demoByGET("+buttonIndex+")");
   //启动一个匿名线程下载图片
new Thread() {
public void run() {
InputStream is=null;
try {
// 定义一个URL对象
URL url = new URL(mUrl1[buttonIndex]);
// 打开和URL之间的连接
URLConnection conn= 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.connect();
// 获取所有响应头字段
Map> map = conn.getHeaderFields();
//显示一下返回的头字段,大家可以学习一下都有哪些扩展属性
for (String key : map.keySet()) {
Log.d("GET", key + "--->" + map.get(key));
}
//检验一下返回的附件类型
List type=map.get("Content-Type");
   if(type != null && type.contains("image/jpeg")){
   
   }
//获取连接的输入流
is=conn.getInputStream();
// 从InputStream中解析出图片放到成员变量mBitmap中,
               // 注意:此种方式应用比较普遍
mBitmap = BitmapFactory.decodeStream(is);
// 发送消息、通知UI组件显示该图片
mImageViewHandler.sendEmptyMessage(0x123);
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(is !=null)
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//设置线程运行结束
mThreadIsRun=false;
}
}
}.start();
}


3.6 步骤5 准备处理demoByPOST函数的处理内容 

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

(3.6.2)根据传入的参数序号提取图片的网址。

(3.6.3)把网址拆分成地址和参数两个部分,利用地址构造一个URL。

(3.6.4)通过 url.openConnection()获取一个连接放到变量conn中。

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

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

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

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

(3.6.9) 获取所有响应头字段,显示一下头字段内容;

(3.6.10)获取输入流,利用BitmapFactory从is中读取Bitmap数据放到mBitmap中;

(3.6.11)继续在线程的run中利用mImageViewHandler发送一个图片下载成功的消息;

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


//POST的演示
private void demoByPOST(final int buttonIndex){
        //如果当前已经有线程在运行,则不要继续
if(mThreadIsRun)
return;
mThreadIsRun=true;
mTextView.setText("等待:demoByPOST("+buttonIndex+")");
   //启动一个匿名线程下载图片
new Thread() {
public void run() {
InputStream is=null;
BufferedReader br=null;
PrintWriter os=null;
try {
// 定义一个URL对象
String[] urlStr=mUrl2[buttonIndex].split("\\?");
URL url = new URL(urlStr[0]);
//URL url = new URL(mUrl1[buttonIndex]);
// 打开和URL之间的连接
URLConnection conn= 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");

//POST是不需要连接   建立实际的连接
//conn.connect();
// 获取URLConnection对象对应的输出流
os = new PrintWriter(conn.getOutputStream());
// 发送请求参数
os.print(urlStr[1]);
// flush输出流的缓冲
os.flush();

// 获取所有响应头字段
Map> map = conn.getHeaderFields();
//显示一下返回的头字段,大家可以学习一下都有哪些扩展属性
for (String key : map.keySet()) {
Log.d("GET", key + "--->" + map.get(key));
}
String result="";
List type=map.get("Content-Type");
   if(type != null && type.contains("text/html")){
// 定义BufferedReader输入流来读取URL的响应
    br = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = br.readLine()) != null)
{
result += "\n" + line;
}
   
   }
//获取连接的输入流
is=conn.getInputStream();
// 从InputStream中解析出图片放到成员变量mBitmap中,
               // 注意:此种方式应用比较普遍
mBitmap = BitmapFactory.decodeStream(is);
// 发送消息、通知UI组件显示该图片
mImageViewHandler.sendEmptyMessage(0x123);
}catch (Exception e){
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.7 步骤6 加入权限 


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


3.8 步骤7 测试,发现POST时不能更新图片,原因在于百度服务POST时返回的是网页,不是图片; 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值