Android网络通信:网络图片查看器

    说明:

       1、本系列博文是博主在学习传智播客Android培训视频的学习笔记

       2、当然博文不只是罗列视频上讲的知识点,通过查阅资料对一些知识点进行了详细的讲解

       3、由于是初学,难免有疏漏之处,还请不吝赐教    

    4、本文关于HttpURLConnection的介绍来自网络,感谢作者,更详细请戳:

       http://www.blogjava.net/supercrsky/articles/247449.html 

        一、场景

        一个简单的应用,用户输入一个图片的URL,点击查看,显示这个URL对应的图片,效果如下:

                    

        二、应用实现

        1、应用的布局,由于开发工具新建应用时,默认以RelativeLayout布局,在布局简单界面时,可能显得有点复杂。建议给EditText一个默认的URL,方便测试。布局代码如下:

  
  
  
  
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     xmlns:tools="http://schemas.android.com/tools" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="match_parent" >  
  5.                              
  6.     <TextView 
  7.         android:layout_width="fill_parent" 
  8.         android:layout_height="wrap_content" 
  9.         android:layout_alignParentLeft="true" 
  10.         android:text="@string/path" 
  11.         android:id="@+id/first" />  
  12.                                  
  13.     <EditText 
  14.         android:layout_width="fill_parent" 
  15.         android:layout_height="wrap_content" 
  16.         android:layout_below="@id/first" 
  17.         android:inputType="text" 
  18.         android:text="http://img1.gtimg.com/sports/pics/hv1/10/188/1237/80483875.jpg" 
  19.         android:id="@+id/imagepath"/>  
  20.                                  
  21.     <Button 
  22.         android:layout_width="wrap_content" 
  23.         android:layout_height="wrap_content" 
  24.         android:layout_below="@id/imagepath" 
  25.         android:text="@string/button" 
  26.         android:id="@+id/btn" 
  27.         android:onClick="search" 
  28.         />  
  29.                                  
  30.     <ImageView 
  31.         android:layout_width="fill_parent" 
  32.         android:layout_height="wrap_content" 
  33.         android:contentDescription="@string/description" 
  34.         android:layout_below="@id/btn" 
  35.         android:id="@+id/image" 
  36.         />  
  37. </RelativeLayout> 

        2、实现Button的click事件,代码如下:

  
  
  
  
  1. public class MainActivity extends Activity {  
  2.                           
  3.     private EditText editText;  
  4.     private ImageView imageView;  
  5.     @Override 
  6.     public void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.main);  
  9.         editText = (EditText)findViewById(R.id.imagepath);  
  10.         imageView = (ImageView)findViewById(R.id.image);  
  11.     }  
  12.                               
  13.     public void search(View v){  
  14.         String url = editText.getText().toString();  
  15.         byte[] data;  
  16.         try {  
  17.             //根据url取得网络图片数据  
  18.             data = ImageService.getImage(url);  
  19.             //创建一个Bitmap(位图图像)  
  20.             Bitmap bmap = BitmapFactory.decodeByteArray(data, 0, data.length);  
  21.             //将bitmap设置到图片显示控件  
  22.             imageView.setImageBitmap(bmap);  
  23.         } catch (Exception e) {  
  24.             e.printStackTrace();  
  25.             Toast.makeText(this.getApplicationContext(), R.string.fail, 1).show();  
  26.         }  
  27.     }  

        3、实现ImageService中的getImage方法,示例如下:

  
  
  
  
  1. /**  
  2.      * 获取网络图片的数据  
  3.      * @param url 图片的网络路径  
  4.      * @return  
  5.      * @throws Exception  
  6.      */ 
  7.     public static byte[] getImage(String url) throws Exception {  
  8.         URL path = new URL(url);  
  9.         // conn对象实际上是根据URL的请求协议(此处是http协议)生成的URLConnection类的子类HttpURLConnection,  
  10.         // 故此处最好将其转化为HttpURLConnection类型的对象,以便用到HttpURLConnection更多的API    
  11.         HttpURLConnection conn = (HttpURLConnection)path.openConnection();  
  12.         conn.setReadTimeout(5000);  
  13.         conn.setRequestMethod("GET");  
  14.         if(conn.getResponseCode()==200){  
  15.             InputStream in = conn.getInputStream();  
  16.             return StreamTools.read(in);  
  17.         }  
  18.         return null;  
  19.     } 

        4、实现StreamTool中的read方法,示例如下:

  
  
  
  
  1. /**  
  2.      * 读取输入流的数据  
  3.      * @param in  
  4.      * @return  
  5.      * @throws Exception  
  6.      */ 
  7.     public static byte[] read(InputStream in) throws Exception{  
  8.         ByteArrayOutputStream out = new ByteArrayOutputStream();  
  9.         byte[] buffer = new byte[1024];  
  10.         int len = 0;  
  11.         while((len=in.read(buffer)) != -1){  
  12.             out.write(buffer);  
  13.         }  
  14.         in.close();  
  15.         return out.toByteArray();  
  16.     } 

        5、配置应用访问网络的权限,否则将抛出java.net.unknownhostException异常,示例如下:

  
  
  
  
  1. <application 
  2.         android:icon="@drawable/ic_launcher" 
  3.         android:label="@string/app_name" 
  4.         android:theme="@style/AppTheme" >  
  5.         <activity 
  6.             android:name=".MainActivity" 
  7.             android:label="@string/title_activity_main" >  
  8.             <intent-filter>  
  9.                 <action android:name="android.intent.action.MAIN" />  
  10.                      
  11.                 <category android:name="android.intent.category.LAUNCHER" />  
  12.             </intent-filter>  
  13.         </activity>  
  14.     </application>  
  15.     <uses-permission android:name="android.permission.INTERNET"/> 

        6、重点知识点介绍:HttpURLConnection类介绍

        (1)、HttpURLConnection参数

  
  
  
  
  1. // 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在http正文内,因此需要设为true, 默认情况下是false;     
  2. httpUrlConnection.setDoOutput(true);     
  3. // 设置是否从httpUrlConnection读入,默认情况下是true;     
  4. httpUrlConnection.setDoInput(true);     
  5. // Post 请求不能使用缓存     
  6. httpUrlConnection.setUseCaches(false);     
  7. // 设定传送的内容类型是可序列化的java对象(如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)     
  8. httpUrlConnection.setRequestProperty("Content-type""application/x-java-serialized-object");     
  9. // 设定请求的方法为"POST",默认是GET     
  10. httpUrlConnection.setRequestMethod("POST");     
  11. // 连接,从上述第2条中url.openConnection()至此的配置必须要在connect之前完成,     
  12. httpUrlConnection.connect(); 

        (2)、HttpURLConnection连接问题

  
  
  
  
  1. // 此处getOutputStream会隐含的进行connect(即:如同调用上面的connect()方法,所以在开发中不调用上述的connect()也可以)。     
  2. OutputStream outStrm = httpUrlConnection.getOutputStream(); 

        (3)、HttpURLConnection总结

         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请求实际上由两部分组成,一个是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(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。 

 

你可能感兴趣的:(android)