android學習二十四(網絡編程的(de)最佳實踐)
發表時(shí)間:2021-1-10
發布人(rén):融晨科技
浏覽次數:57
前面的(de)博客已經講解了(le/liǎo)HttpURLConnection和(hé / huò)HttpClient的(de)用法,知道(dào)了(le/liǎo)如何發起HTTP請求,以(yǐ)及解析服務器返回
的(de)數據。但是(shì)可能你發現了(le/liǎo),因爲(wéi / wèi)一個(gè)應用程序很多地(dì / de)方都可能使用網絡功能,而(ér)發送HTTP請求的(de)代碼基本相同,如果每次我們都去編寫一遍發送HTTP請求的(de)代碼,這(zhè)顯然不(bù)太好。
通常情況下我們都應該将這(zhè)些通用的(de)網絡操作提取到(dào)一個(gè)公共的(de)類裏,并提供一個(gè)靜态方法,當想要(yào / yāo)發起網絡請求的(de)時(shí)候隻需簡單地(dì / de)調用一下這(zhè)個(gè)方法即可。比如下面的(de)寫法:
package com.jack.networktest; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpUtil { public static String sendHttpRequest(String address){ HttpURLConnection connection=null; try{ URL url=new URL(address); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setDoInput(true); connection.setDoOutput(true); InputStream in=connection.getInputStream(); BufferedReader reader=new BufferedReader(new InputStreamReader(in)); StringBuilder response=new StringBuilder(); String line; while((line=reader.readLine())!=null){ response.append(line); } return response.toString(); }catch(Exception e){ e.printStackTrace(); return e.getMessage(); }finally{ if(connection!=null){ connection.disconnect(); } } } }
以(yǐ)後每當要(yào / yāo)發起一條HTTP請求的(de)時(shí)候就(jiù)可以(yǐ)這(zhè)樣寫:
String address="http://www.baidu.com";
String response=HttpUtil.sendHttpRequest(address);
在(zài)獲取到(dào)服務器響應的(de)數據後我們就(jiù)可以(yǐ)對它進行解析和(hé / huò)處理了(le/liǎo)。但是(shì)需要(yào / yāo)注意,網絡請求通常都是(shì)屬于(yú)耗時(shí)操作,而(ér) sendHttpRequest方法的(de)内部并沒有開啓線程,這(zhè)樣就(jiù)可能導緻在(zài)調用sendHttpRequest方法的(de)時(shí)候使得主線程阻塞住。你可能說(shuō),在(zài)sendHttpRequest方法内部開啓一個(gè)線程不(bù)就(jiù)解決了(le/liǎo)阻塞這(zhè)個(gè)問題了(le/liǎo)嘛。其實沒那麽簡單,因爲(wéi / wèi)如果我們在(zài)sendHttpRequest方法中開啓了(le/liǎo)一個(gè)線程來(lái)發起HTTP請求,那麽服務器響應的(de)數據是(shì)無法進行返回的(de),所有的(de)耗時(shí)邏輯都是(shì)在(zài)子(zǐ)線程裏進行的(de),sendHttpRequest方法會在(zài)服務器還來(lái)得及響應的(de)時(shí)候就(jiù)執行結束了(le/liǎo),當然也(yě)就(jiù)無法返回響應的(de)數據了(le/liǎo)。
那麽這(zhè)種情況該如何解決?其實解決方法可以(yǐ)使用java的(de)回調機制,下面就(jiù)讓我們來(lái)學習一下回調機制到(dào)底如何使用的(de)。
首先需要(yào / yāo)定義一個(gè)接口,比如将它命名成HttpCallbackListener,代碼如下所示:
public interfac HttpCallbackListener{
void onFinish(String response);
void onError(Exception e);
}
可以(yǐ)看到(dào),我們在(zài)接口中定義了(le/liǎo)兩個(gè)方法,onFinish(String response)方法表示當服務器成功響應我們請求
的(de)時(shí)候調用,onError(Exception e)表示當進行網絡操作出(chū)現錯誤的(de)時(shí)候調用。這(zhè)兩個(gè)方法都帶有參數,
onFinish(String response)方法中的(de)參數代表着服務器返回的(de)數據,而(ér)onError(Exception e)方法
中的(de)參數記錄着錯誤的(de)詳細信息。
接着修改HttpUtil中的(de)代碼:
import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpUtil { public static void sendHttpRequest(final String address, final HttpCallbackListener listener){ new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub HttpURLConnection connection=null; try{ URL url=new URL(address); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setDoInput(true); connection.setDoOutput(true); InputStream in=connection.getInputStream(); BufferedReader reader=new BufferedReader(new InputStreamReader(in)); StringBuilder response=new StringBuilder(); String line; while((line=reader.readLine())!=null){ response.append(line); } if(listener!=null){ //回調onFinish()方法 listener.onFinish(response.toString()); } }catch(Exception e){ if(listener!=null){ //回調onError()方法 listener.onError(e); } }finally{ if(connection!=null){ connection.disconnect(); } } } }).start(); } }
我們首先給sendHttpRequest方法添加了(le/liǎo)一個(gè)HttpCallbackListener參數,并在(zài)方法的(de)内部開啓了(le/liǎo)一個(gè)子(zǐ)線程,然後
在(zài)子(zǐ)線程裏去執行具體的(de)網絡操作。注意子(zǐ)線程中是(shì)無法通過return語句來(lái)返回數據的(de),因此這(zhè)裏我們将服務器響應的(de)數據傳入了(le/liǎo)HttpCallbackListener的(de)onFinish()方法中,如果出(chū)現了(le/liǎo)異常就(jiù)将異常原因傳入到(dào)onError()方法中。
現在(zài)sendHttpRequest方法接收兩個(gè)參數了(le/liǎo),因此我們在(zài)調用它的(de)時(shí)候還需要(yào / yāo)将HttpCallbackListener的(de)實例傳入
如下所示:
HttpUtil.sendHttpRequest(address,new HttpCallbackListener(){ public void onFinish(String response){ //在(zài)這(zhè)裏根據返回内容執行具體的(de)邏輯 } public void onError(Exception e){ //在(zài)這(zhè)裏對異常進行處理 } });
這(zhè)樣的(de)話,當服務器成功響應的(de)時(shí)候我們就(jiù)可以(yǐ)在(zài)onFinish方法裏對響應數據進行處理了(le/liǎo),類似地(dì / de),如果出(chū)現了(le/liǎo)異常,就(jiù)可以(yǐ)在(zài)onError方法裏對異常情況進行處理。如此一來(lái),我們就(jiù)巧妙的(de)利用回調機制将響應數據成功返回給調用方了(le/liǎo)。
另外需要(yào / yāo)注意的(de)是(shì),onFinish方法和(hé / huò)onError方法最終還是(shì)在(zài)子(zǐ)線程中運行的(de),因此我們不(bù)可以(yǐ)在(zài)這(zhè)裏執行任何的(de)
UI操作,如果需要(yào / yāo)根據返回的(de)結果來(lái)更新UI,則仍然要(yào / yāo)使用異步消息處理機制。
http://blog.csdn.net/j903829182/article/details/42521437