Android學習筆記(四五):互聯網通訊-HttpClient、XML解析(W3C)

前幾日Android發佈了4.0 Icecream,昨天上網發現Begining Book中有Edition 3的版本,比對一下,仍是有至關的改動,不只僅增長了tablet的部分,對原有的章節有有一些修訂,先後的調整等等。先按Edtion 2的順序看,相同章節的看Edtion 3,而後回頭看Edition 3的Chapter 2四、25(E2的36)、2六、2七、2八、2九、4四、4五、4六、47幾個新增章節。同時將模擬器改成Android 2.3的版本,已適應可能新增的改動。html

訪問Internet是設備的一個重要用戶,以前學習過如何嵌入Webkit,此外咱們能夠經過API來訪問Intenet。Android提供Apache HttpClient庫,基於此,其餘協議,能夠視爲在HTTP封裝的格式,例如XML,JSON等。HTTP Client的詳細資料可在http://hc.apache.org/中獲取。node

Android提供三個XML的解析器: 一、傳統的W3C DOM parser(org.w3c.dom); 二、SAX解析器(org.xml.sax); 三、以前Android學習筆記(三八):資源resource(上)中使用XmlPullParser。 另外提供JSON解析器(org.json)。固然也可使用第三方的解析器。 實現的步驟以下:android

  1. 建立HttpClient接口的對象,能夠經過DefaultHttpClient來建立。
  2. 請求和HttpRequest相幫定,包括HttpGet,HttpPost,然手執行經過execute()來執行請求。
  3. 可使用HttpResponsed對象處理返回,帶有response code(例如200,即200 OK),Http頭等,另外能夠在execute()中攜帶ResponseHandler做爲參數,將在此返回response body,然則此法可行但不推薦,由於一般來說咱們應該response code。

下面是一個天氣widget的小例子,採用HttpClient,是以哦那個HttpGet發出對某個URL(google的天氣查詢網絡頁面)請求,返回xml格式的天氣信息,從中分析,並將結果經過WebKit Browser的方式程序,下面是查找廣州天氣的返回。在例子中,第一學習HttpClient的用法,第二也學習XML的解析,這次採用W3C DOM解析器,經過NodeList和Element來進行分析。web


<xml_api_reply version="1">  
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0"> 
<forecast_information>  <!-- 查詢地點信息,只給出準備分析的部分 -->
    … …  
    <postal_code data="廣州"/>  
    <forecast_date data="2011-10-27"/>  
</forecast_information> 
<current_conditions>  <!-- 給出當前的天氣狀況,只顯示準備分析的部分 -->
    <condition data="局部多雲"/>  
    <temp_c data="27"/> 
    <humidity data="溼度: 48%"/> 
    <icon data="/ig/images/weather/partly_cloudy.gif"/> 
    <wind_condition data="風向: 北、風速:2 米/秒"/> 
</current_conditions>   
<forecast_conditions>  <!-- 給出當每天氣預報 -->
    <day_of_week data="週四"/> 
    <low data="21"/> 
    <high data="28"/> 
    <icon data="/ig/images/weather/mostly_sunny.gif"/> 
    <condition data="以晴爲主"/> 
</forecast_conditions> 
<forecast_conditions> <!-- 給出明每天氣預報 -->
      ... ... 
</forecast_conditions> 
<forecast_conditions> <!-- 給出後每天氣預報 -->
      … … 
</forecast_conditions> 
<forecast_conditions> <!-- 給出第三每天氣預報 -->
      … … 
</forecast_conditions> 
</weather> 
</xml_api_reply>apache

程序代碼以下:json

(這個接口屬於iGoogle的私有接口,已經被關閉,能夠找其餘的weather api,例如http://www.wunderground.com/weather/api/。 Wei , 2012.9 )api

public class Chapter25Test1 extends Activity{ 
    private WebView browser = null;  //採用WebView來排版顯示的內容
    private HttpClient client = null; 
    private List<Forecast> forecasts = new ArrayList<Forecast>();  //採用List來保存將來幾天的天氣狀況 
    private CurrentWeather currentCondition = null;  //保存即時天氣狀況和地點時間 
    private String format = "http://www.google.com/ig/api?hl=zh-cn&weather=%1s"; //Google XML天氣信息的查詢API接口
     
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.chapter_25_test1);
        browser = (WebView) findViewById(R.id.c131_webkit);
        //步驟一、建立HttpClient接口的對象,能夠經過DefaultHttpClient來建立。
        client = new DefaultHttpClient(); 
    }  

     protected void onResume() {  
        super.onResume(); 
        updateForecast("廣州");  //步驟二、向Internet請求廣州的天氣信息,獲取信息,並呈現
    }  

    protected void onDestroy() {  
        super.onDestroy(); 
        //步驟三、釋放HttpClient的資源,此步沒詳細跟蹤,按字面估計如一直鏈接無回覆,則在Activity Destroy的時候,終止鏈接
        client.getConnectionManager().shutdown(); 
    }  

    //步驟二、向Internet請求廣州的天氣信息,獲取信息,並呈現 
    private void updateForecast(String citycode ){ 
        String url = String.format(format, citycode); 
        //步驟2.一、生成HttpGet請求,並經過execute( )向Internet發出,在responseHandler中獲得返回值。
        HttpGet getMethod = new HttpGet(url); 
        try{ 
            ResponseHandler<String> responseHandle = new BasicResponseHandler();
            String responseBody = client.execute(getMethod,responseHandle);
            buildForecasts(responseBody);  //步驟2.2 從返回中獲取天氣信息
            String page = generatePage();   //步驟2.3 經過HTML在webkit browser中呈現
            browser.loadDataWithBaseURL(null, page, "text/html", "UTF-8", null);
        }catch(Throwable t){  
            Toast.makeText(this,"Request failed : "+ t.toString(), 5000).show();
        } 
    } 
    //步驟2.2 從返回中獲取天氣信息,注意這種帶throws Exception的寫法
    private void buildForecasts(String raw) throws Exception{    
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = builder.parse(new InputSource(new StringReader(raw))); 
        //獲取即時天氣信息和地點、時間信息,方式和後面獲取將來天氣預報同樣,較爲繁瑣,略過,信息存放在currentCondition中
         …. ….  

        //對於XML<node_name  node_attribute=attribute_valule> node_vaule </node_name> 
        NodeList furCondition = doc.getElementsByTagName("forecast_conditions");
        //有將來四日天氣預報,分別取出 
        for(int i = 0 ; i < furCondition.getLength(); i ++){ 
            Element e = (Element)furCondition.item(i); 
            addWeather(e); 
        } 
    } 
    private void addWeather( Element e){ 
        Forecast fc = new Forecast(getWeatherAttribute(e,"day_of_week"),
                                                  getWeatherAttribute(e,"low"), 
                                                  getWeatherAttribute(e,"high"), 
                                                  getWeatherAttribute(e,"icon"), 
                                                  getWeatherAttribute(e,"condition"));
        forecasts.add(fc); 
    }  
     
    //下面是從每組Element中讀取所需信息,另外補充的是若是愛用Node,例如e.getFirstClide()獲取,也能夠 node.getAttributes().getNamedItem("data").getNodeValue() 來得到攜帶的屬性值
    private String getWeatherAttribute(Element e, String name){ 
        NodeList t = e.getElementsByTagName(name); 
        Element a = (Element)t.item(0); 
        return a.getAttribute("data"); 
    }  

     //步驟2.3 經過HTML在webkit browser中呈現 
    private String generatePage(){ 
        StringBuilder bufResult  = new StringBuilder("<html><body><table width=\"100%\">");
        bufResult.append("<h2><font color=\"red\">" + currentCondition.getCity() + "</font></h2>\n"); 
        … … //顯示即時信息
        bufResult.append ("<table><tr><th width=\"25%\">Time</th>"+ 
        "<th width=\"25%\">溫度</th><th colspan=\"2\" width=\"50%\">天氣狀況</th></tr>");
        for(Forecast forecast : forecasts){ 
            bufResult.append("<tr><td align=\"center\">");
            bufResult.append(forecast.getDate()); 
            bufResult.append("</td><td align=\"center\">"); 
            bufResult.append(forecast.getTemperature()); 
            bufResult.append("</td><td align=\"right\">"); 
            bufResult.append(forecast.getCondition()); 
            bufResult.append("</td><td align=\"left\"><img src=\"http://www.google.com/");
            bufResult.append(forecast.getIcon()); 
            bufResult.append("\"></td></tr>");  
        } 
        bufResult.append("</table></body></html>"); 
        return bufResult.toString(); 
    } 
    private class Forecast{  
         …. /* 存放天氣預報信息,並提供get獲取方法*/ ….. 
    } 
    private class CurrentWeather{  
       …. /* 存放當前天氣、時間、地點,並提供get獲取方法*/ …. 
    } 
cookie

經過經緯度獲取當地天氣網絡

在Google的天氣預報api中,也是能夠輸入經緯度,格式爲:http://www.google.com/ig/api?hl=zh-cn&weather=,,,23080000,113170000,這是廣州的經緯度。Android能夠經過GPS獲取經緯度,而後所謂輸入參數,能夠獲得當前所在地的天氣。在模擬器中,能夠經過預先配置經緯度來進行個模擬。先打開模擬器,而後在Eclipse的菜單Window -> Open Perspective -> DDMS,進入配置,可在Control Panel中設置所需的經緯度。如右圖所示。多線程

定位服務之後再學習。

須要注意

若是是要使用SSL協議,HttpClient並不支持。主要是由於須要決定如何處理SSL證書,是否接受全部證書,包括私有或者已通過期的正確,或者是否須要提示用戶。

簡單的HttpClient在缺省下做爲單線程使用。若是須要多線程,能夠設置HttpClient支持多線程。

AndroidHttpClient

從Android2.2(API level 8)開始,可使用AndroidHttpClient類,在android.net.http中,是HttpClient接口的一個實現,就如例子中的DefaultHttpClient。經過這個類,能夠進行SSL管理;可經過靜態方法newInstance來直接填寫userAgent(report in your HTTP requests)並獲取AndroidHttpClient的實例,能夠在HTTP頭能增長date信息,支持gzip壓縮的內容。

和傳統的DefaultHttpClient不一樣,AndroidHttpClient不會自動保存cookies,可經過HttpContext對象來處理。

此外,AndroidHttpClient不容許主線程使用,只能在後臺線程運行。這點須要特別注意。

相關連接:個人Andriod開發相關文章

相關文章
相關標籤/搜索