android重新学_网络1——采用HttpURLConnection获取网络图片

      随着3G、4G的普及、通信资费的降低,网络的覆盖率、网络速率比以前有很大提升,这就给我们在手机上访问互联网带来了很大方便,因此做安卓应用程序开发,很多时候我们都需要和互联网打交道。纯本地的应用越来越少。学会开发网络应用成为一名android应用开发者的基本功。

     这一次,我们就一起做一个网络图片查看器的小Demo。

一 页面布局

     首先,界面布局上如下图所示:一个垂直布局的线性布局,里面有显示图片的imageview和用于输入图片网络地址的edittext和点击就能够获取图片的button.

下面就是布局文件的代码:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3               android:orientation="vertical"
 4               android:layout_width="fill_parent"
 5               android:layout_height="fill_parent"
 6         >
 7     <ImageView android:layout_width="match_parent"
 8                android:layout_height="match_parent"
 9                android:layout_weight="1"
10                android:id="@+id/img_net"/>
11     <EditText
12             android:layout_width="fill_parent"
13             android:layout_height="wrap_content"
14             android:id="@+id/et_path"
15             android:hint="请输入图片的网络路径"
16             />
17     <Button
18             android:layout_width="fill_parent"
19             android:layout_height="wrap_content"
20             android:id="@+id/btn_img"
21             android:gravity="center"
22             android:text="查看"
23             />
24 </LinearLayout>

大家可能注意到了ImageView中的android:layout_weight="1"属性了,这个demo中是想把从网络上获取的图片最大化展示,所以宽和高都用了match_parent,但是用match_parent,其他两个控件就会被挤到屏幕外面去,所以会使用这个属性,关于这个属性的使用可以参考下面的解释:

android:weight:属性是指渲染的权重,只有指定高度或者宽度为0dp的时候,weight才会代表当前控件渲染的权重。如果指定当前的控件是fill_parent(或者是wrap_content).那weight就不代表权重了,它代表渲染的优先级。值越大代表优先级越低。这时默认的优先级都是0.

 

二.实现原理

布局写好了,在写java代码获取图片之前,让我们先来看看PC端的浏览器是如何获取一张图片的。通过httpwatch这款抓包工具,很简单的帮我们了解获取过程。

 

在我们输入网址敲击回车之后,浏览器是实际上做了一个http的get方式的网络请求,返回的resultCode是200,代表请求成功,我们还可以看一下左边具体流的数据,

蓝色线标注的是请求的路径;

黑色线代表的是接收的类型;

红色线代表的是浏览器的一些数据;

黄色线代表的是访问的主机;

而右边的内容则是服务器返回的消息

Content-Length代表的是返回数据的总长度,这里也就是图片的大小;

下面的一些乱码则是传输回来的数据。通过这个抓包的过程,我们知道从互联网上获取图片的操作无非就是http的一个get请求。我们需要指定一下,请求的路径,然后把返回回来的数据拿到。一张图片就获取到了。同样的,我们安卓客户端的代码也可以仿照这样去写。

三.代码实现

MyActivity.java

  1 package com.example.getNetPic;
  2 
  3 import android.app.Activity;
  4 import android.graphics.Bitmap;
  5 import android.graphics.BitmapFactory;
  6 import android.os.Bundle;
  7 import android.os.Handler;
  8 import android.os.Message;
  9 import android.text.TextUtils;
 10 import android.view.View;
 11 import android.widget.EditText;
 12 import android.widget.ImageView;
 13 import android.widget.Toast;
 14 
 15 import java.io.IOException;
 16 import java.net.HttpURLConnection;
 17 import java.net.MalformedURLException;
 18 import java.net.URI;
 19 import java.net.URL;
 20 import java.util.logging.LogRecord;
 21 
 22 public class MyActivity extends Activity {
 23 
 24     final static int MESSAGE_SHOW_IMG = 0;
 25     final static int MESSAGE_RESULT_ERR = 1;
 26 
 27     Handler handler;
 28 
 29     @Override
 30     public void onCreate(Bundle savedInstanceState) {
 31         super.onCreate(savedInstanceState);
 32         setContentView(R.layout.main);
 33         handler = new Handler(){
 34             @Override
 35             public void handleMessage(Message msg) {
 36                // super.handleMessage(msg);
 37                 switch (msg.what){
 38                     case MESSAGE_SHOW_IMG:
 39                         ((ImageView)findViewById(R.id.img_net)).setImageBitmap((Bitmap)msg.obj);
 40                         break;
 41                     case  MESSAGE_RESULT_ERR:
 42                         Toast.makeText(MyActivity.this,"获取失败",Toast.LENGTH_SHORT).show();
 43                         break;
 44                     default:
 45                         break;
 46                 }
 47             }
 48         };
 49         // 为了在真机上演示方便,预先设置了路径
 50         ((EditText)findViewById(R.id.et_path)).setText("http://pic19.nipic.com/20120218/3096297_185027882000_2.jpg");
 51         findViewById(R.id.btn_img).setOnClickListener(new View.OnClickListener() {
 52             @Override
 53             public void onClick(View v) {
 54                 String path = ((EditText)findViewById(R.id.et_path)).getText().toString().trim();
 55                 if (TextUtils.isEmpty(path)){
 56                     Toast.makeText(MyActivity.this,"请输入图片的网络路径",Toast.LENGTH_SHORT).show();
 57                 } else {
 58                     requestNetByThread(path);
 59                 }
 60             }
 61         });
 62     }
 63 
 64     /*
 65     * android4.0以后,为了提高用户体验
 66     * 访问网络不能再UIThread中,需开启一个子线程
 67     * */
 68     private void requestNetByThread(String path) {
 69         new Thread(){
 70             @Override
 71             public void run() {
 72                 //super.run();
 73               requestNet(path);
 74             }
 75         }.start();
 76     }
 77 
 78     private void requestNet(String path) {
 79         try {
 80             //1.使用路径包装类URL包装路径
 81             URL url = new URL(path);
 82             //2.调用openConntention()方法,建立连接
 83             /*
 84             * 在互联网上,其实有很多访问的类型。
 85             * 我们常见的有httpconnection类型,还有httpsconnection这种经过加密的类型,
 86             * ftp的类型,这些类型都是基于url的。这里我们需要的是httpUrlconnection.
 87             * 这种也是继承自Urlconnnution,所以这里我们进行一下强转
 88             * */
 89             HttpURLConnection connection = (HttpURLConnection)url.openConnection();
 90             //3.与互联网(服务器)之间的连接搭好后,进行连接设置
 91             //3.1 设置请求方式,这里我们设置成get
 92             connection.setRequestMethod("GET");
 93             //3.2设置请求服务器超时的时间,单位是毫秒
 94             connection.setConnectTimeout(5000);
 95             //下面的设置注掉是因为这些不是必需设置的。
 96             //3.3设置读取的超时时间,单位是毫秒
 97             //connection.setReadTimeout(60000);
 98             //3.4设置其他请求参数
 99             //connection.setRequestProperty();
100             //3.5 接收服务器返回的结果码
101             int code = connection.getResponseCode();
102             //3.6 对结果码进行判断,200,400,500
103             if (code == 200){
104                 //请求成功,接收服务器返回的流数据
105                 /*
106                 * 由于是显示图片,我们就直接使用android提供给我们的
107                 * BitmapFactroy工具类调用方法将输入流转化成位图bitmap
108                 * */
109                 Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream());
110                 //3.7 创建一个消息,发送给主线程
111                 Message message = new Message();
112                 //3.8 设置消息的数据
113                 message.obj = bitmap;
114                 //3.9 设置消息的类型值
115                 message.what = MESSAGE_SHOW_IMG;
116                 //4.0 发送消息到handler
117                 handler.sendMessage(message);
118             } else{
119                 //请求失败,同样也发送消息
120                 Message message = new Message();
121                 //3.9 设置消息的类型值
122                 message.what = MESSAGE_RESULT_ERR;
123                 //4.0 发送消息到handler
124                 handler.sendMessage(message);
125             }
126 
127         } catch (Exception e) {
128             e.printStackTrace();
129             //失败,同样也发送消息
130             Message message = new Message();
131             //3.9 设置消息的类型值
132             message.what = MESSAGE_RESULT_ERR;
133             //4.0 发送消息到handler
134             handler.sendMessage(message);
135         }
136     }
137 }

记得,最后添加访问网络权限。

效果图:

 

注意:

访问网络的操作会比较耗时。谷歌为了提高用户体验,在4.0以上的系统里,谷歌做了一个判断,请求访问网络的操作是不允许在主线程里执行的。

重点代码:

URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
//connection.setReadTimeout(60000);
//connection.setRequestProperty();
int code = connection.getResponseCode();

其他:

这个demo也隐含涉及了其他的知识点:

1.非UI线程使用Hnadler向UI线程发送消息

2.ANR

3.Bitmap

 

另外,我已经将代码上传到这里

posted @ 2015-10-11 19:30  404map  Views(2138)  Comments(0Edit  收藏  举报