3.Android HTTP请求方式之HttpURLConnection
引言:
好了,前两节我们已经对HTTP协议进行了学习。相信看完前两节的朋友对HTTP协议相比之前
应该更加熟悉吧。好吧。学了要用,相信非常多人都知道Android中HTTP的两种最主要的请求方式 他们各自是:HttpURLConnection和HttpClient。当然了解了最主要的两个后,我们实际开发中 可能并不会自己去慢慢写网络请求的代码,毕竟依据不同的web端接口,我们须要组织不同的数据 内容上传。这明显会添加我们的代码量,所以一般我们都会使用第三方的网络框架来请求网络, 经常使用的有volley,android-async-http,async-http-client,utils。loopj等等。有非常多,前面我们也说过 我们会解说retrofit封装我们的HTTP请求。一些基础的东西还是要会的,面试说不定会问呢, 并且了解底层的东西,看别人的框架的代码也不会一头雾水是吧,嗯,就唠叨这么多。開始本节内容~
两者的差别:
在学习他们两个的详细使用方法之前,我们先来对照下这两种方式有什么差别:
HttpURLConnection:继承至URLConnection,抽象类。无法直接实例化对象。通过调用openCollection( )方法获得对象实例,默认是带gzip压缩的。 HttpClient则是Apache给我们提供的HTTP訪问网络接口。相同也是无法直接创建实例的。而是通过 new DefaultHttpClient( )获得对象实例,默认不带gzip~ 另外他们请求connection都是keep alive,而默认的User-Agent不同 前者是:Dalvik/16.0(Linux;U;Android 4.2.0;Lenovo S898T/4.6.13) 后者是:Apach-Http/UNAVAILABLE(java 1.4) 另外,Android API 22版本号后HttpClient就被无情的抛弃了~
HttpURLConnection的使用
①使用步骤:
- 创建一个URL对象: URL url = new URL();
- 调用URL对象的openConnection( )来获取HttpURLConnection对象实例: HttpURLConnection conn = (HttpURLConnection) url.openConnection( );
- 设置HTTP请求使用的方法:GET或者POST conn.setRequestMethod(“GET”);
- 设置连接超时,读取超时的毫秒数,以及server希望得到的一些消息头 conn.setConnectTimeout(6*1000); conn.setReadTimeout(6 * 1000);
- 调用getInputStream( )方法获得server返回的输入流,然后输入流进行读取了 InputStream in = conn.getInputStream( );
- 最后调用disconnect( )方法将HTTP连接关掉 conn.disconnect( );
另外除了上面这些外,有时我们还可能须要对响应码进行推断,比方200:
if(conn.getResponseCode( ) != 200)然后一些处理 还有,可能有时我们并不须要传递什么參数,而是直接去訪问一个页面。我们能够直接用: final InputStream in = new URL(“url”).openStream(); 然后直接读流。只是这种方法适合于直接訪问页面的情况。底层实现事实上也是return openConnection().getInputStream(),并且我们还不能设置一些请求头的东东,用不用能够自己掂量掂量②代码实例:
在開始每一个详细的样例编写前,我们先来编写一个工具类,用于将流转化为二进制数组:
StreamTool.java:
package com.jay.example.utils;import java.io.ByteArrayOutputStream;import java.io.InputStream;public class StreamTool { //从流中读取数据 public static byte[] read(InputStream inStream) throws Exception{ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while((len = inStream.read(buffer)) != -1) { outStream.write(buffer,0,len); } inStream.close(); return outStream.toByteArray(); }}
1.发送GET请求:
好了,那么接下来我们就来写个简单的样例来熟悉HttpURLConnection的使用方法吧:
先看执行的效果。然后我们再看实现代码,执行截图:恩呢。看完执行效果,我们来開始写代码,我们程序的功能是:
定义了一个上下文菜单,通过点击不同的菜单项,做一些不同的网络请求, 载入图片,载入网页代码,依据代码载入网页到WebView中 由于篇幅原因。直接贴核心代码。要细致研究的能够自行下载代码參考处理网络请求的类:GetData.java:
package com.jay.example.httpurlconnectiondemo.util;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;public class GetData { // 定义一个获取网络图片数据的方法: public static byte[] getImage(String path) throws Exception { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 设置连接超时为5秒 conn.setConnectTimeout(5000); // 设置请求类型为Get类型 conn.setRequestMethod("GET"); // 推断请求Url是否成功 if (conn.getResponseCode() != 200) { throw new RuntimeException("请求url失败"); } InputStream inStream = conn.getInputStream(); byte[] bt = StreamTool.read(inStream); inStream.close(); return bt; } // 获取网页的html源码 public static String getHtml(String path) throws Exception { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (conn.getResponseCode() == 200) { InputStream in = conn.getInputStream(); byte[] data = StreamTool.read(in); String html = new String(data, "UTF-8"); return html; } return null; }}
代码非常easy,然后是MainActivity.java:
package com.jay.example.httpurlconnectiondemo;import com.jay.example.httpurlconnectiondemo.util.GetData;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.os.Handler;import android.view.ContextMenu;import android.view.ContextMenu.ContextMenuInfo;import android.view.MenuInflater;import android.view.MenuItem;import android.view.View;import android.view.Window;import android.webkit.WebView;import android.widget.ImageView;import android.widget.ScrollView;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity { private TextView txtMenu, txtshow; private ImageView imgPic; private WebView webView; private ScrollView scroll; private Bitmap bitmap; private String detail=""; private boolean flag = false; private final static String PIC_URL = "http://d.hiphotos.baidu.com/image/pic/item/b03533fa828ba61e0bd9f7ef4534970a304e593e.jpg"; private final static String HTML_URL = "http://www.baidu.com"; // 用于刷新界面 private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case 0x001: hideAllWidget(); imgPic.setVisibility(View.VISIBLE); imgPic.setImageBitmap(bitmap); Toast.makeText(MainActivity.this, "图片载入完成", Toast.LENGTH_SHORT).show(); break; case 0x002: hideAllWidget(); scroll.setVisibility(View.VISIBLE); txtshow.setText(detail); Toast.makeText(MainActivity.this, "HTML代码载入完成", Toast.LENGTH_SHORT).show(); break; case 0x003: hideAllWidget(); webView.setVisibility(View.VISIBLE); webView.loadDataWithBaseURL("",detail, "text/html","UTF-8",""); Toast.makeText(MainActivity.this, "网页载入完成", Toast.LENGTH_SHORT).show(); break; default: break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); initView(); setView(); } private void initView() { txtMenu = (TextView) findViewById(R.id.txtMenu); txtshow = (TextView) findViewById(R.id.txtshow); imgPic = (ImageView) findViewById(R.id.imgPic); webView = (WebView) findViewById(R.id.webView); scroll = (ScrollView) findViewById(R.id.scroll); } private void setView() { registerForContextMenu(txtMenu);// webView.getSettings().setDefaultTextEncodingName("UTF-8"); } // 定义一个隐藏全部控件的方法: private void hideAllWidget() { imgPic.setVisibility(View.GONE); scroll.setVisibility(View.GONE); webView.setVisibility(View.GONE); } @Override // 重写上下文菜单的创建方法 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { MenuInflater inflator = new MenuInflater(this); inflator.inflate(R.menu.menus, menu); super.onCreateContextMenu(menu, v, menuInfo); } // 上下文菜单被点击是触发该方法 @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.one: new Thread() { public void run() { try { byte[] data = GetData.getImage(PIC_URL); bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); } catch (Exception e) { e.printStackTrace(); } handler.sendEmptyMessage(0x001); }; }.start(); break; case R.id.two: new Thread() { public void run() { try { detail = GetData.getHtml(HTML_URL); } catch (Exception e) { e.printStackTrace(); } handler.sendEmptyMessage(0x002); }; }.start(); break; case R.id.three: if(detail.equals("")){ Toast.makeText(MainActivity.this, "先请求HTML先嘛~", Toast.LENGTH_SHORT).show(); }else{ handler.sendEmptyMessage(0x003); } break; } return true; }}
注意事项:
用handler的原因就不用讲了吧~
另外我们载入html代码的使用的是webView的loadDataWithBaseURL而非LoadData。假设用LoadData又要去纠结中文乱码的问题,so…用loadDataWithBaseURL就能够不用纠结那么多了 另外有些页面可能须要我们提交一些參数,比方账号password:我们仅仅需把相应參数拼接到url尾部就可以。比方:passwd=123&name=Jack
然后服务端getParamater(“passwd”)这样就能够获得相应的參数了,我们请求时这些东西都会看得清清楚楚,所以GET方式并不安全
2.发送Post请求
有GET自然有POST,我们通过openConnection获取到的HttpURLConnection默认是进行Get请求的,
所以我们使用POST提交数据,应提前设置好相关的參数:conn.setRequestMethod(“POST”); 还有:conn.setDoOutput(true);conn.setDoInput(true);设置同意输入,输出 还有:conn.setUseCaches(false); POST方法不能缓存,要手动设置为false,详细实现看代码: 核心代码:PostUtils.java
package com.jay.example.httpurlconnectiondemo.util;import java.io.ByteArrayOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;public class PostUtils { public static String LOGIN_URL = "http://172.16.2.54:8080/HttpTest/ServletForPost"; public static String LoginByPost(String number,String passwd) { String msg = ""; try{ HttpURLConnection conn = (HttpURLConnection) new URL(LOGIN_URL).openConnection(); //设置请求方式,请求超时信息 conn.setRequestMethod("POST"); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); //设置执行输入,输出: conn.setDoOutput(true); conn.setDoInput(true); //Post方式不能缓存,需手动设置为false conn.setUseCaches(false); //我们请求的数据: String data = "passwd="+ URLEncoder.encode(passwd, "UTF-8")+ "&number="+ URLEncoder.encode(number, "UTF-8"); //这里能够写一些请求头的东东... //获取输出流 OutputStream out = conn.getOutputStream(); out.write(data.getBytes()); out.flush(); if (conn.getResponseCode() == 200) { // 获取响应的输入流对象 InputStream is = conn.getInputStream(); // 创建字节输出流对象 ByteArrayOutputStream message = new ByteArrayOutputStream(); // 定义读取的长度 int len = 0; // 定义缓冲区 byte buffer[] = new byte[1024]; // 依照缓冲区的大小,循环读取 while ((len = is.read(buffer)) != -1) { // 依据读取的长度写入到os对象中 message.write(buffer, 0, len); } // 释放资源 is.close(); message.close(); // 返回字符串 msg = new String(message.toByteArray()); return msg; } }catch(Exception e){e.printStackTrace();} return msg; }}
执行效果图:
总结:
好的。本节关于HttpURLConnection的内容就到这里,主要介绍了两种不同的请求方式的实现,GET和POST,代码是比較简单的,就多多解释了~另外,另一些复杂的东西。以后有机会再深究…
下节我们来学习的是Apache为我峨嵋你提供的HttpClient。操作会更加简单。敬请期待~