Android網絡與數據存儲——網絡編程數據處理(網絡請求,解析xml,解析Json)

手機的優勢是攜帶方便,可以隨時打開,而且手機通常總是處于聯網狀態的,所以網絡支持對于手機很重要。而且Java的網絡編程完全適用于Android網絡編程。

一.網絡請求


1.URL

在真正學習網絡請求之前有必要了解一下什么是URL,URL的英文全拼是Uniform Resource Locator,翻譯過來為統一資源定位器,大概意思就是URL是指向互聯網資源的指針。

這里說的資源可以是文件或目錄,也可以是對象的引用,例如對數據庫或搜索引擎的查詢。

URL的組成:協議名、主機、端口和資源。即滿足如下格式:

protocol://host:port/resourceName

例如 google的URL地址:

https://www.google.com

URL類提供了多個構造器用于創建URL對象,一旦獲得了URL對象之后,就可以訪問該URL對象對應的資源了。

2.Http網絡請求

Android中的Http網絡請求有兩種方式:

  • HttpURLConnection
  • HttpClient(已不推薦使用)

既然HttpClient已被棄用,那就用HttpURLConnection。

HttpURLConnection繼承了URLConnection,可用于向指定網站發送GET請求、POST請求。提供了一下方法:

  • HttpURLConnection openConnection():返回一個HttpURLConnection對象,表示到URL所引用的遠程對象的連接。
  • int getResponseCode():獲取服務器的響應代碼。例如:200表示服務器成功響應,404表示沒響應。
  • String getResponseMessage():獲取服務器的響應消息。
  • String getRequestMethod():獲取發送請求的方法。
  • void setRequestMethod():設置發送請求的方法。
  • void setConnectTimeout():設置連接超時時間。
  • void setReadTimeout():設置讀取超時時間。

下邊寫一個請求百度API獲取全國城市的方法來使用上面提到的方法。代碼如下:

public void requestCityData(final String urlString) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(urlString);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    connection.connect();
                    if (connection.getResponseCode() == 200) {
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                        String line;
                        StringBuilder builder = new StringBuilder();
                        while ((line = reader.readLine()) != null) {
                            builder.append(line);
                        }
                        reader.close();
                        String result = builder.toString();
                        Message msg = new Message();
                        msg.what = 0;
                        msg.obj = result;
                        handler.sendMessage(msg);
                    }
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
}

從以上代碼可以看出請求網絡數據的方法可以分為以下步驟:

  • 創建URL對象url。
  • 通過url.openConnection()獲取HttpURLConnection對象connection。
  • 設置請求方式、連接延遲、讀取延遲、連接。
  • 通過connection.getResponseCode()獲取響應碼來判斷是否連接成功。
  • 如果連接成功,接下來的讀取文件和Java的讀文件操作一樣。
  • 由于請求網絡數據的操作屬于耗時操作,所以應該把整個請求操作放在了子線程(處理異步數據有兩種方式:handler和AsyncTask,這里用handler進行實現,下一篇中的利用多線程下載會用AsyncTask),最后把請求到的數據通過handler.sendMessage()方法發送到主線程,在handler中的handleMessage()方法中對請求到的數據進行處理。handler代碼如下:
Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    String cityData = msg.obj.toString();
                    Log.d("CityActivity", cityData);
                    break;
            }
        }
};

這里的handler只是簡單的打印了一下請求到的數據。

到目前為止,還不算請求完成,因為這里用到了網絡,要想獲取網絡上的數據,該應用必須有請求網絡的權限,在AndroidManifest.xml中加入網絡權限即可。

<uses-permission android:name="android.permission.INTERNET" />

二.解析xml


如果請求到的數據為xml類型的,就需要把xml類型的數據解析成我們想要的類型或從xml類型的數據中解析出我們想要的數據。

解析xml類型數據有兩種方式:

  • SAX:基于事件驅動的解析(解析器+事件處理器),較復雜。
  • PULL
  • DOM:基于文件流。

SAX、PULL是一個標簽一個標簽讀,分段加載;DOM是整個文件讀取出來,然后加載。

1.SAX

利用SAX解析如下xml中的id、url以及item text。

<?xml version="1.0" encoding="utf-8"?>
<web>
    <item id = "0" url = "http://www.baidu.com" >百度</item>
    <item id = "1" url = "http://www.sogou.com" >搜狗</item>
    <item id = "2" url = "http://www.sohu.com" >搜狐</item>
</web>

先新建一個SAXParseHandler類繼承自DefaultHandler,并實現startDocument()、startElement()、characters()、endElement()、endDocument()這五個方法。

public class SAXParseHandler extends DefaultHandler {

    private List<WebURL> mWebURLs;
    private WebURL mWebURL;
    private boolean state = false;

    @Override
    public void startDocument() throws SAXException {
        mWebURLs = new ArrayList<>();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        mWebURL = new WebURL();
        if (TextUtils.equals(localName, "item")){
            for (int i = 0; i < attributes.getLength(); i++) {
                if (TextUtils.equals(attributes.getLocalName(i), "id")){
                    mWebURL.setmID(Integer.parseInt(attributes.getValue(i)));
                }else if (TextUtils.equals(attributes.getLocalName(i), "url")){
                    mWebURL.setmUrl(attributes.getValue(i));
                }
            }
            state = true;
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        String content = String.valueOf(ch, start, length);
        if (state) {
            mWebURL.setmContent(content);
            state = false;
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (TextUtils.equals(localName, "item")){
            mWebURLs.add(mWebURL);
        }
    }

    @Override
    public void endDocument() throws SAXException {
    }
}

以上代碼中startDocument()表示解析到最外層的標簽,進行一些初始化操作,startElement()表示解析到子標簽,通過attributes來獲取該標簽的屬性id和url,characters()表示子標簽開始標簽和結束標簽中間的內容,在這里通過轉換ch可以獲取到,endElement()表示結束子標簽,在這個方法中將獲取到的信息進行保存,endDocument()表示解析結束。

SAXParseHandler類將xml的每一個標簽進行了遍歷,接下來就是通過SAX解析器進行解析了。解析代碼如下:

private void testSAXParse() throws ParserConfigurationException, SAXException, IOException {
        //定義一個factory API,能夠配置和獲取一個SAX解析器去解析xml
        //SAXParserFactory.newInstance();返回Android的接口SAXParserFactory,不像其他Java接口,該方法不能產生系統屬性
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();//屬性文件或服務API
        //定義一個API包裹XMLReader實現類
        SAXParser saxParser = saxParserFactory.newSAXParser();
        //讀一個xml文檔的接口,用于回調
        XMLReader xmlReader = saxParser.getXMLReader();
        saxParseHandler = new SAXParseHandler();
        //將saxParseHandler的實例設置到XMLReader中
        xmlReader.setContentHandler(saxParseHandler);
        InputStream inputStream = getResources().openRawResource(R.raw.test);
        InputSource inputSource = new InputSource(inputStream);
        //開始執行解析
        xmlReader.parse(inputSource);
    }

以上代碼中的注釋寫的很詳細,就不在啰嗦了。

2.PULL

待補充...

三.解析Json


Android中解析Json的類有JSONObject和JSONArray。

格式化Json數據的網址:jsonlint.com

開源庫:對開源庫還未進行研究,待研究了回來補充...

  • GSON
  • fastJson

通過JSONObject和JSONArray來對下面一段Json數據進行解析。

{city_info: [ 
{city: "南子島", cnty: "中國", id: "CN101310230", lat: "11.26", lon: "114.20", prov: "海南" }, 
{city: "北京", cnty: "中國", id: "CN101010100", lat: "39.904000", lon: "116.391000", prov: "直轄市" }, ... 
] }

寫一個方法對以上Json數據進行解析,代碼如下:

public List<CityInfo> parseCityData(String cityData) {
        List<CityInfo> cityInfos = new ArrayList<>();
        try {
            JSONObject jsonObject = new JSONObject(cityData);
            JSONArray jsonArray = jsonObject.getJSONArray("city_info");

            for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject cityObject = (JSONObject) jsonArray.get(i);
                String city = cityObject.getString("city");
                String prov = cityObject.getString("prov");
                CityInfo cityInfo = new CityInfo(city, prov);
                cityInfos.add(cityInfo);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return cityInfos;
}

通過new JSONObject()獲取整個JSONObject對象,然后利用getJSONArray()獲取city_info對應的Json數組,然后再通過Json數組的get方法獲取數組中的每一個JSONObject對象,通過關鍵字獲取我們想要的數據,最后將數據存入列表。整個Json數據解析完畢。

四.網絡狀態處理


網絡狀態處理:可以判斷是否連接網絡,還可以區分移動網絡流量還是WiFi網絡流量

  • ConnectivityManager
  • NetworkInfo

五.擴展


  1. 下載電影、音樂的本質?
    網絡請求
  2. 斷點下載
    記錄http的Head,下載時間,下載了哪些東西。
  3. 常用網絡開源庫
  • android-async-http
  • volley
  • OKHttp
  • Retrofit
  1. 封裝請求及通用設置
  • 封裝能用Header
  • 請求參數封裝
  1. 封裝結果處理
  • 能用錯誤碼處理
  • 數據轉換校驗
  1. 攔截請求設置及代理
  • Fiddler(Windows)
  • Charles(Mac)
  • wifi設置代理
  1. 技巧
  • Postman查詢API
  • Restful API
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 1 XML解析No29 【 XML:可拓展標記語言,語言和HTML類似,也是一種標記語言。 特點:標記是自定義...
    征程_Journey閱讀 1,684評論 0 9
  • JSON JSON和XML都是需要解析的 JSON是一種輕量級的數據格式,一般用于數據交互服務器返回給客戶端的數據...
    JonesCxy閱讀 1,877評論 2 10
  • 從小是個無肉不歡的我特別喜歡的就是過年,因為每逢過年的時候家里就會燒一桌子好吃的,當然必少不了我最愛吃的紅燒肉。 ...
    3f17274cd933閱讀 401評論 0 0
  • 多希望有一天突然驚醒,發現自己在高中的一節課上睡著了,現在經歷的一切都是一場夢,桌上滿是你的口水。你告訴同桌...
    風雪依然閱讀 338評論 0 1