AndroidHttpClient結構:
public final class AndroidHttpClient extends Object implements HttpClient
前言:這類其實是Google對阿帕奇的HttpClient的一個封裝,一些默認屬性有android做了一些優化。
然后阿帕奇的HttpClient是對java中HttpUrlConnection的一個封裝,感覺阿帕奇封裝的還是不錯的,
特別是其中的HttpEntity,很強大也很好用,能在android手機上上傳百M的文件到服務器,還是不錯的。
一:AndroidHttpClient的使用方式
1.創建AndroidHttpClient對象
AndroidHttpClient c = AndroidHttpClient.newInstance("");
AndroidHttpClient只能通過以上方法建立,其中的參數好像是設置代理的,如果沒有置空即可。
2.使用開啟cookies
AndroidHttpClient默認情況下是關閉cookies的,開啟的方法如下
AndroidHttpClient c = AndroidHttpClient.newInstance("");
BasicHttpContext context = new BasicHttpContext();
context.setAttribute(ClientContext.COOKIE_STORE, new BasicCookieStore());
try {
c.execute(null, context);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
其中的context在client發送的請求的時候,同時發送即可。發送請求方法的第一個參數,很重要,下面詳解。
二:HttpUriRequest使用
1.上面的c.execute(null, context);第一個參數即為HttpUriRequest,用於封裝請求信息的。
HttpUriRequest提供了兩個使用的子類,相信你閉着眼睛也能猜到,沒錯!就是HttpGet和HttpPost。
2.ok,我們先來看看,HttpGet是怎么用的。
題外話,其實從這個方法的名字上就能看出來,get嘛,
就是獲取的得到的意思,所以如果你想從服務器獲取什么數據,就多用用他吧。
HttpGet提供了三個構造函數:
——HttpGet()
——HttpGet(URI uri)
——HttpGet(String uri)
看上面的最后兩個構造方法,你應該能猜到那個參數的意義了,就是想要
獲取文件的地址!其實第一個雖然沒有提供一個地址,但是HttpGet有個
方法可以設置資源地址:HttpGet.setURI(URI uri);
看下他的具體初始化方式:
方式一:
try { final String _URI = "www.baidu.com"; HttpGet requestGet = new HttpGet(); requestGet.setURI(new URI(_URI)); } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); }
方式二:
try { final String _URI = "www.baidu.com"; HttpGet requestGet = new HttpGet(new URI(_URI)); } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); }
方式三:
final String _URI = "www.baidu.com"; HttpGet requestGet = new HttpGet(_URI);
3.好了,當創建好了HttpGet對象之后,就可以將其放入AndroidHttpClient訪問了。
有人說使用Get方式訪問的時候,能不能在后面添加用戶名和密碼什么的,其實加不加
都可以,因為在服務器那邊獲取的方式是一樣的,但是我覺得如果有參數的話,還是不要
直接加在資源地址后面吧,因為我感覺太難看了。。。看起來不整潔,哈哈。
那有人說了,那怎么有參數的時候怎么辦呢?下面就給你解決的方案,HttpPost閃亮登場!
4.HttpPost這個東西,其實最NB的地方是他能放入一個實體(Entity)發送到服務器,這個
實體能夠封裝各種數據,將想發送的數據封裝到Entity中,然后調用HttpPost的setEntity方法
將實體放入其中,然后發送請求就行了。所以下面就好講解一下Entity的都能封裝什么類型的數據。
HttpPost的初始化方式和HttpGet一樣的,就是將HttpGet換成HttpPost就行了。
三:HttpEntity講解(本博文的重點)
1.有的同學可能會覺得,看博文文字太多看的很是無聊,來張圖片多好。既然大家有着要求,那就滿足你。
要是覺得圖片看着不是清晰,可以將圖片拖拽到桌面,慢慢欣賞。
2.上面的圖片顯示了HttpEntity的大致結構,interface和abstract我就不多說了,
其實也沒什么說的,就是定義了一些方法,但是還沒實現,等着之后的class來具體實現的,
打個比喻,interface就是項目經理,class就是咱們這些**了,所以還是來說說我們吧。
——InputStreamEntity:他就是將一個IO流封裝到實體中,這個東西很NB,經過我的實測,
能發送百M的數據到服務器,而且不是OOM(內存溢出),之前做一個視頻拍攝,然后上傳的
項目的時候,就遇到過視頻上傳的時候會有OOM問題,后來用分割上傳的方式解決了,但是直
到發現這個方法的時候,發現阿帕奇已經給准備好了,還得多看書啊。
我這里是讀取的assets下的一個文件,將其轉換為io流,然后放入了實體中。在new這個實體的
時候,需要提供一個int參數,這個參數的數值可以小於或等於IO流的大小,否則會報錯,當參數
的數值小於IO的大小時,會截取上傳IO,比如IO流的內容是阿拉伯數字 1到10,而參數數值你用了5
那服務器只能接收到1 2 3 4 5.
try { // 讀取assets中的文件將其轉換為io流 InputStream is = getActivity().getAssets().open("Text.xml"); mEntitys.add(new InputStreamEntity(is, is.available())); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
——ByteArrayEntity:將byte數組封裝到實體中,有的時候你可能獲取到了一個byte對象,而不是io對象,
所以直接使用這個方法就可以將byte封裝到實體中,而不用轉換一下。
try { // 讀取assets中的文件將其轉換為io流 InputStream is = getActivity().getAssets().open("Text.xml"); // 定義一個字節數組封裝io流 byte[] b = new byte[is.available()]; // 將io讀入到數組中 is.read(b); mEntitys.add(new ByteArrayEntity(b)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
——StringEntity:這個實體還是比較使用的,他能直接將一個字符串封裝到實體中,我看過
有人用這個東西去發送圖片,就是將圖片轉成byte,然后在轉成Base64編碼的數據,再添加到
這個實體中,其實我感覺這個就是放字符串的,就不要將圖片什么的,放進來了,畢竟還有專門
放文件的實體呢對吧?
try { // 創建一個字符串 String str = "Hello world"; mEntitys.add(new StringEntity(str)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); }
——UrlEncodedFormEntity:將請求的內容進行格式化了,其實這個方法同時簡化的客戶端發送,
也簡化了服務器端獲取,服務器通過getParameters(String name)即可獲取到傳送來的信息。
方便的原因是將發送的信息鍵值對化了,鍵值對,你懂得,就是一個Key對應一個Value唄,所以客戶端
需要創建一個鍵值對對象即:NameValuePair。而UrlEncodedFormEntity為了一次能發送多個鍵值對,
參數采用了集合的方式:List<NameValuePair>。
/** * 服務器端,只需要使用getParameters(String name)即可獲得屬性值 */ try { // post請求,需要一個K-V集合數組,來保存請求的信息,並將其放去請求實體中 List<NameValuePair> postParameters = new ArrayList<NameValuePair>(); // 添加屬性對 postParameters.add(new BasicNameValuePair("name", "android")); mEntitys.add(new UrlEncodedFormEntity(postParameters)); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); }
——SerializableEntity:這個東西JB太強大了,不好意思爆粗口了,因為真的很NB,相信很多朋友在獲取服務器,
或是上傳東西到服務器的時候,都遇到這樣的問題,比如獲取用戶列表,有很多用戶,通常是服務器返回xml或是json,
然后我們再去解析,生成一個JavaBean對象,對吧,然后在創建一個集合將這些對象放進去,很是繁瑣,特別是解析的時候,
可是如果你使用SerializableEntity這個實體的時候,你會發現,生活原來如此美好,因為你可以直接將序列化的對象放入實體中,
然后發送,客戶端或是服務器可以直接接受這個對象!聽明白了嗎?你不需要解析什么xml或是json,直接就能獲取到這個對象了!
是不是很NB,但是NB需要有前提的,就是你的服務器得是Java的,所以和IOS平台交互的時候,還得需要json什么的。。。。
*有一點一定要注意,使用他的時候,被序列化的對象所在包的包名,服務器和客戶端必須一致,必須哦,其實可以做一個jar包,然后
服務器和客戶端一起使用。
package com.xhm.Test.Http; import java.io.Serializable; public class Student implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
/** * 在使用這個實體的時候要注意,對象的bean所在的包名要是服務器上的一致,否則會有問題。 */ try { // 創建對象 Student student = new Student(); student.setName("Name"); student.setAge(11); mEntitys.add(new SerializableEntity(student, true)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
——FileEntity:這個也真心NB,直說吧,我將一個450M的rmvb的電影成功上傳的服務器上了,服務器正常打開觀看。
媽媽再也不同擔心我的OOM問題了。而且這個使用起來還很簡單,只要提供文件的路徑和文件類型就行了。
/** * 這個實體,能夠封裝一些比較大的實體,比如上百M的文件等 * * 上傳的時候,注意本demo沒有做進度條,在成功上傳之后,會返回上傳文件的大小 */ // 創建文件路徑,這個視頻是在SD卡中的,大概有50M大小 File file = new File("/sdcard/DCIM/dashipin.mp4"); mEntitys.add(new FileEntity(file, "*/*"));
——EntityTemplate:說實話,這個實體我還不清楚,究竟怎么去使用,或是應用什么場景,反正他有點
特別,因為需要一個ContentProducer對象來初始化。
// 創建ContentProducer對象 ContentProducer producer = new ContentProducer() { @Override public void writeTo(OutputStream outstream) throws IOException { // TODO Auto-generated method stub Writer writer = new OutputStreamWriter(outstream); writer.write("hello"); writer.write("world"); writer.flush(); writer.close(); } }; mEntitys.add(new EntityTemplate(producer));
好了上面就是HttpEntity的一些東西,有什么不對的地方,希望批評指正!謝謝。
四:里面使用到的一些方法
1.執行請求和解析反饋的結果
/** * 執行post網絡訪問 * * @param entity * 請求實體 */ private void executePost(final HttpPost request, final HttpEntity entity) { try { request.setEntity(entity); // 連接服務器,並獲得反饋的response mResponse = mClient.execute(request); // 從反饋的response中獲得輸入流 BufferedReader mReader = new BufferedReader(new InputStreamReader( mResponse.getEntity().getContent())); Message msg = new Message(); msg.obj = "UpLoad請求\n" + BR2SB(mReader).toString(); mHandler.sendMessage(msg); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
/** * 將BufferedReader轉換為StringBuffer * * @param br * @throws IOException */ protected StringBuffer BR2SB(BufferedReader br) throws IOException { StringBuffer sb = new StringBuffer(""); String line = null; while ((line = br.readLine()) != null) { sb.append(line + "\n"); } return sb; }
mHandler = new Handler(new Callback() { @Override public boolean handleMessage(Message msg) { // TODO Auto-generated method stub mTextView.setText(msg.obj.toString()); return false; } });
提示:因為android為了安全在3.0之后不允許將HTTP請求放在主線程中,所以必須使用Thread,所以這里也使用的handler來發送http反饋的信息!