Android学习笔记(四五):互联网通信-HttpClient、XML解析(W3C)

前几日Android发布了4.0 Icecream,昨天上网发现Begining Book中有Edition 3的版本,比对一下,还是有相当的改动,不仅仅增加了tablet的部分,对原有的章节有有一些修订,前后的调整等等。先按Edtion 2的顺序看,相同章节的看Edtion 3,然后回头看Edition 3的Chapter 24、25(E2的36)、26、27、28、29、44、45、46、47几个新增章节。同时将模拟器改为Android 2.3的版本,已适应可能新增的改动。

访问Internet是设备的一个重要用户,之前学习过如何嵌入Webkit,此外我们可以通过API来访问Intenet。Android提供Apache HttpClient库,基于此,其他协议,可以视为在HTTP封装的格式,例如XML,JSON等。HTTP Client的详细资料可在http://hc.apache.org/中获取。

Android提供三个XML的解析器: 1、传统的W3C DOM parser(org.w3c.dom); 2、SAX解析器(org.xml.sax); 3、之前Android学习笔记(三八):资源resource(上)中使用XmlPullParser。 另外提供JSON解析器(org.json)。当然也可以使用第三方的解析器。 实现的步骤如下:

  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来进行分析。


<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>

程序代码如下:

(这个接口属于iGoogle的私有接口,已经被关闭,可以找其他的weather api,例如http://www.wunderground.com/weather/api/。 Wei , 2012.9 )

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);
        //步骤1、创建HttpClient接口的对象,可以通过DefaultHttpClient来创建。
        client = new DefaultHttpClient(); 
    }

protected void onResume() {  
        super.onResume(); 
        updateForecast("广州");  //步骤2、向Internet请求广州的天气信息,获取信息,并呈现
    }

protected void onDestroy() {  
        super.onDestroy(); 
        //步骤3、释放HttpClient的资源,此步没详细跟踪,按字面估计如一直连接无回复,则在Activity Destroy的时候,终止连接
        client.getConnectionManager().shutdown(); 
    }

//步骤2、向Internet请求广州的天气信息,获取信息,并呈现 
    private void updateForecast(String citycode ){ 
        String url = String.format(format, citycode); 
        //步骤2.1、生成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获取方法*/ …. 
    } 
}

通过经纬度获取当地天气

在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开发相关文章

时间: 2024-10-26 06:04:54

Android学习笔记(四五):互联网通信-HttpClient、XML解析(W3C)的相关文章

Android 学习笔记 6 组件通信及广播消息(一)

Intent的概念 Intent的官方解释是“An Intent is a messaging object you can use to request an action from another app component. ”这里的app component就是指安卓activity,service,contentprovider,broadcastreceiver四大组件.不同的intent可以使这些组件产生相应的动作,为这些组件之间提供了交互能力.那么这个“messaging obj

Android 学习笔记 7 组件通信及广播消息(二)

Intent隐式启动Activity 隐式启动的好处在于不需要在第一个组件中指明需要启动另外的哪一个组件,而由Android系统来决定,这样有利于降低组件之间的耦合度. 选择隐式启动Activity,Android系统会在程序运行时解析Intent,并根据一定的规则对Intent和组件进行匹配,使Intent上的action.data和category与目标Activity吻合.匹配的组件可以是程序本身的Activity,也可以是Android系统内置的Activity,还可以是第三方应用程序提

Android学习笔记(九) AndroidManifest.xml

AndroidManifest为组件配置其各种属性以及权限 1.permission的设置,可以通过设置自定义权限限制使用,另外还可对permissionLevel的设置实现访问权限的管理 2.配置android:process可以实现同一应用内的多进程,通过设置这个属性,可以使得同一应用内的不同组件之间实现不同进程的效果,从而使得应用内的组件的开发有了更大的灵活性.

Android学习笔记(二二): 多页显示-Tag的使用

在手机屏幕中,Tab也是比较常用的,通常和List结合,例如我们手机的通信录.下面是Tag的结构. TabHost是整个Tab的容器,包括两部分,TabWidget和FrameLayout.TabWidget就是每个tab的标签,FrameLayout则是tab内容. 如果我们使用extends TabAcitivty,如同ListActivity,TabHost必须设置为@android:id/tabhost TabWidget必须设置android:id为@android:id/tabs F

Android学习笔记(四六):互联网通信-文件下载

在Android 2.3引入了DownloadManager可以处理复杂的文件下载,包括检查用户是否有数据联系(WIFI或者移动数据),当用户从一个有数据连接的地方移动到无连接的地方(例如离开了wifi或者3G data的access point),确保设备在下载过程中保持awake状态.DownloadManager可以处理HTTP URLs,但是不能处理HTTPS(SSL) URLs. 设置下载文件条件许可 在这个例子,将学习通过DownloadManager从Internet下载文件,并存

android学习笔记36——使用原始XML文件

XML文件 android中使用XML文件,需要开发者手动创建res/xml文件夹. 实例如下: book.xml==> <?xml version="1.0" encoding="utf-8"?> <books> <book publishDate="2016.05.05" price="88.6">android学习笔记</book> <book publishD

【转】 Pro Android学习笔记(六七):HTTP服务(1):HTTP GET

目录(?)[-] HTTP GET小例子 简单小例子 出现异常NetworkOnMainThreadException 通过StrictMode进行处理 URL带键值对 Andriod应用可利用service提供很多功能,例如利用Google Maps API,现在我们将聚焦在HTTP serice中. Android SDK提供HttpClient,和J2EE中的接口非常相似.最常用的就是HTTP GET和HTTP POST.相关内容也可以阅读Android学习笔记(四五):互联网通信-Htt

Android学习笔记二

17. 在ContentProvider中定义的getType()方法是定义URI的内容类型. 18. SQLiteDatabase类中的insert/delete/update/query方法其实也挺好用的,我在EquipmentProvider类中做了实现 19. Android专门有个单元测试项目(Android Test Project),在这个项目中,可以新建一个继承AndroidTestCase类的具体测试类来单元测试某个功能.我新建了一个AndroidTestProject项目,在

【转】 Pro Android学习笔记(七四):HTTP服务(8):使用后台线程AsyncTask

目录(?)[-] 5秒超时异常 AsyncTask 实现AsyncTask抽象类 对AsyncTask的调用 在哪里运行 其他重要method 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件,转载须注明出处:http://blog.csdn.net/flowingflying/ 之前,我们直接在activity中执行http通信,在通信过程中可能会出现连接超时.socket超时等情况,超时阈值一般是秒级,例如AndroidHttpClient中设置的20秒,如果出现超时,就