说明:
1、本系列博文是博主在学习传智播客Android培训视频的学习笔记
2、当然博文不只是罗列视频上讲的知识点,通过查阅资料对一些知识点进行了详细的讲解
3、由于是初学,难免有疏漏之处,还请不吝赐教
4、本文关于HttpURLConnection的介绍来自网络,感谢作者,更详细请戳:
http://www.blogjava.net/supercrsky/articles/247449.html
一、场景
一个简单的应用,用户输入一个图片的URL,点击查看,显示这个URL对应的图片,效果如下:
二、应用实现
1、应用的布局,由于开发工具新建应用时,默认以RelativeLayout布局,在布局简单界面时,可能显得有点复杂。建议给EditText一个默认的URL,方便测试。布局代码如下:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:text="@string/path"
- android:id="@+id/first" />
- <EditText
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/first"
- android:inputType="text"
- android:text="http://img1.gtimg.com/sports/pics/hv1/10/188/1237/80483875.jpg"
- android:id="@+id/imagepath"/>
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/imagepath"
- android:text="@string/button"
- android:id="@+id/btn"
- android:onClick="search"
- />
- <ImageView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:contentDescription="@string/description"
- android:layout_below="@id/btn"
- android:id="@+id/image"
- />
- </RelativeLayout>
2、实现Button的click事件,代码如下:
- public class MainActivity extends Activity {
- private EditText editText;
- private ImageView imageView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- editText = (EditText)findViewById(R.id.imagepath);
- imageView = (ImageView)findViewById(R.id.image);
- }
- public void search(View v){
- String url = editText.getText().toString();
- byte[] data;
- try {
- //根据url取得网络图片数据
- data = ImageService.getImage(url);
- //创建一个Bitmap(位图图像)
- Bitmap bmap = BitmapFactory.decodeByteArray(data, 0, data.length);
- //将bitmap设置到图片显示控件
- imageView.setImageBitmap(bmap);
- } catch (Exception e) {
- e.printStackTrace();
- Toast.makeText(this.getApplicationContext(), R.string.fail, 1).show();
- }
- }
- }
3、实现ImageService中的getImage方法,示例如下:
- /**
- * 获取网络图片的数据
- * @param url 图片的网络路径
- * @return
- * @throws Exception
- */
- public static byte[] getImage(String url) throws Exception {
- URL path = new URL(url);
- // conn对象实际上是根据URL的请求协议(此处是http协议)生成的URLConnection类的子类HttpURLConnection,
- // 故此处最好将其转化为HttpURLConnection类型的对象,以便用到HttpURLConnection更多的API
- HttpURLConnection conn = (HttpURLConnection)path.openConnection();
- conn.setReadTimeout(5000);
- conn.setRequestMethod("GET");
- if(conn.getResponseCode()==200){
- InputStream in = conn.getInputStream();
- return StreamTools.read(in);
- }
- return null;
- }
4、实现StreamTool中的read方法,示例如下:
- /**
- * 读取输入流的数据
- * @param in
- * @return
- * @throws Exception
- */
- public static byte[] read(InputStream in) throws Exception{
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int len = 0;
- while((len=in.read(buffer)) != -1){
- out.write(buffer);
- }
- in.close();
- return out.toByteArray();
- }
5、配置应用访问网络的权限,否则将抛出java.net.unknownhostException异常,示例如下:
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" >
- <activity
- android:name=".MainActivity"
- android:label="@string/title_activity_main" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- <uses-permission android:name="android.permission.INTERNET"/>
6、重点知识点介绍:HttpURLConnection类介绍
(1)、HttpURLConnection参数
- // 设置是否向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();
(2)、HttpURLConnection连接问题
- // 此处getOutputStream会隐含的进行connect(即:如同调用上面的connect()方法,所以在开发中不调用上述的connect()也可以)。
- 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(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。