1. 程式人生 > >基於Http協議的Android網路程式設計

基於Http協議的Android網路程式設計

寫在前面的話:好一陣子沒寫部落格了,心裡有點慚愧。在這期間我主要做了兩件事:一、之前在研究Android的過程中比較吃力,主要是Java的一些基礎知識掌握得還不太好,於是近半個月惡補了一下Java基礎,我發現自己連多型!多型!多型!(重要的事說三遍)這個面向物件的核心知識點都沒掌握,說起來真是太慚愧了,我都不知道自己在不懂多型這個知識點的情況下,是怎麼把Android的核心知識學下來的,要知道在Java以及Android的API中到處都是多型,現在打死我也能把多型發生的必要條件說出來了:1、要有類的繼承(或介面的實現);2、要有方法的重寫;3、要有父類引用指向子類物件。除了多型,托馬士兵老師的福(學了馬士兵Java視訊教程),我把Java程式碼在堆疊中的執行機制學了下,較好的理解了Java程式碼的記憶體執行機制,理解了這些再看Android程式碼,感覺比以前輕鬆多了!套用馬士兵老師的一句話,就是“掌握了Java程式碼在記憶體中的執行機制,就掌握了一切!” 二、除了夯實Java基礎,我還把郭霖前輩(《第一行程式碼》的作者)的部落格仔細研究了一下,不得不說郭大神除了程式碼寫的好,文筆也很棒,當初選擇《第一行程式碼》作為Android學習的入門書籍,絕對是正確決定。在部落格中,郭神通過原始碼的解讀,詳細剖析了Android中初學者不容易掌握的知識點,對於我這種菜鳥,絕對值得反覆研究,當然了,目前涉及到Android原始碼的內容,我還暫時無法理解,不過以後我會慢慢把它搞明白!:)

之前寫過一篇Android網路程式設計《淺談android網路程式設計》,隨著瞭解了更多Android知識,我意識到HttpClient已經不推薦使用了,更是在Android 6.0中被廢棄了,原因之一就是比起HttpURLConnection,HttpClient的封裝性更好,導致其可擴充套件性較差,當然現在網路程式設計更多的是使用框架了,HttpURLConnection被封裝了,socket也被封裝了,而像OKHttp和Volley這種框架,使用起來極為方便,開發者甚至不需要知道http、TCP/IP協議的相關知識就能高效地進行網路通訊,但在有些時候,當開發者遇到bug或是修改些涉及到基於原理的功能時,可能會因為沒能理解這些框架的原理而無法實現,所以本文就通過案例,著重分析基於Http協議的Android網路的原理實現,而不使用框架實現,當然更多的還是基礎知識。

基於Http協議的Android程式設計知識點概要

Android平臺網路相關API介面

  • java.net.*(標準Java介面)
    java.net.*提供與聯網有關的類,包括流、資料包套接字(socket)、Internet協議、常見Http處理等。比如:建立URL,以及URLConnection/HttpURLConnection物件、設定連結引數、連結到伺服器、向伺服器寫資料、從伺服器讀取資料等通訊。這些在Java網路程式設計中均有涉及。
  • Org.apache介面
    對於大部分應用程式而言JDK本身提供的網路功能已遠遠不夠,這時就需要Android提供的Apache HttpClient了。它是一個開源專案,功能更加完善,為客戶端的Http程式設計提供高效、最新、功能豐富的工具包支援。
  • Android.net.*(Android網路介面)
    常常使用此包下的類進行Android特有的網路程式設計,如:訪問WiFi,訪問Android聯網資訊,郵件等功能。

網路架構主要有兩種模式B/S,C/S

  • B/S:瀏覽器/伺服器端模式,通過應用層的HTTP協議通訊,不需要特定客戶端軟體,而是需要統一規範的客戶端,簡而言之就是Android網路瀏覽器(如chrome,UcWeb,QQ瀏覽器等等)訪問web伺服器端的方式。
  • C/S:客戶端/伺服器端模式,通過任意的網路協議通訊,需要特定的客戶端軟體。

伺服器端返回客戶端的內容有三種方式

  • 以HTML程式碼的形式返回;
  • 以XML字串的形式返回。通過XML解析(SAX、DOM,Pull 等)
  • 以json物件的方式返回

Http協議簡介

Http是Internet中廣泛使用的協議,幾乎所有的計算機語言和SDK都會不同程度地支援HTTP,而以網路著稱的Google公司自然也會使Android SDK擁有強大的HTTP訪問能力。在Android SDK中可以採用多種方式使用HTTP,例如HttpURLConnection、HttpClient ( HttpGet、HttpPost )等。
Http是一個屬於應用層的面向物件的協議,由於其簡捷、快速的方式,適用於分散式超媒體資訊系統。它於1990年提出,經過幾年的使用與發展,得到不斷地完善和擴充套件。
Http協議的主要特點如下:

  • 支援C/S模式;
  • 簡單快速:客戶向伺服器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規定了客戶端與伺服器聯絡的型別不同。由於HTTP協議簡單,使得HTTP伺服器的程式規模小,因而通訊速度很快。
  • 靈活:HTTP允許傳輸任意型別的資料物件。正在傳輸的型別由Content-Type加以標記。
  • 無連線:無連線的含義是限制每次連線只處理一個請求。伺服器處理完客戶的請求,並收到客戶的應答後,即斷開連線。採用這種方式可以節省傳輸時間。
  • 無狀態:HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺少狀態意味著如果後續處理需要前面的資訊,則它必須重傳,這樣可能導致每次連線傳送的資料量增大。另一方面,在伺服器不需要先前資訊時它的應答就較快。

HttpURLConnection類

HttpURLConnection類是jdk中的標準網路介面,該類的全限定名是java.net.HttpURLConnection,下面將介紹利用HttpURLConnection實現get請求和post請求。

HttpURLConnection實現GET請求

這裡寫圖片描述

HttpURLConnection實現get請求步驟如下:

  1. 獲得需要訪問的server地址、方法、及引數鍵值;
  2. 建立URL物件,將上述訪問地址傳入;
  3. 呼叫URL.openConnection()方法返回HttpURLConnection物件;
  4. 呼叫HttpURLConnection.connect()方法連線server;
  5. 呼叫HttpURLConnection.respondCode()方法,根據返回碼判斷server返回是否正確;
  6. 呼叫HttpURLConnection.getInputStream()方法讀取server返回的內容;
  7. 關閉流、呼叫HttpURLConnection.disconnect()方法斷開連線。

示例如下:
首先在介面中新增一個按鈕,點選該按鈕,程式將嘗試請求上述server的相應資料並返回給程式,介面如下:
這裡寫圖片描述

程式碼示例:

public class MainActivity extends AppCompatActivity {
    private Button mButtonHttpUrlConnctionGet;
    private String mUrl = "http://cloud.bmob.cn/0906a62b462a3082/";
    private String mMethod = "getMemberBySex";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButtonHttpUrlConnctionGet = (Button) findViewById(R.id.button_httpurlconnection_get);
        mButtonHttpUrlConnctionGet.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                doGet("boy");

            }
        });

    }

    //doGet請求
    private void doGet(String s) {
    //1、獲得需要訪問的server地址、方法、及引數鍵值
        final String serverAddress = mUrl + mMethod + "?" + "sex=" + s;
        //訪問網路,開啟一個執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                //2、建立URL物件,將上述訪問地址傳入;
                    URL url = new URL(serverAddress);
                    //3、呼叫URL.openConnection()方法返回HttpURLConnection物件
                    HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
                    //4、呼叫HttpURLConnection.connect()方法連線server
                    httpUrlConnection.connect();
                    //5、呼叫HttpURLConnection.respondCode()方法,根據返回碼判斷server返回是否正確
                    if (httpUrlConnection.getResponseCode() == 200) {
                        //6、呼叫HttpURLConnection.getInputStream()方法讀取server返回的內容
                        InputStream is = httpUrlConnection.getInputStream();
                        //包裝流:位元組流->轉換字元流(處理流)->緩衝字元流(處理流)

                        BufferedReader br = new BufferedReader(new InputStreamReader(is));
                        StringBuffer sb = new StringBuffer();
                        String readLine = "";
                        while ((readLine = br.readLine()) != null) {
                            sb.append(readLine);

                        }
                        //7、關閉流、呼叫HttpURLConnection.disconnect()方法斷開連線
                        is.close();
                        br.close();

                        httpUrlConnection.disconnect();
                        //Log日誌中顯示返回結果

                        Log.i("TAG", sb.toString());


                    } else {

                        Log.e("TAG", "failed to connect server!");
                    }


                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();

                }
            }
        }).start();


    }
}

LogCat顯示結果如下所示:
這裡寫圖片描述

使用HttpURLConnection的get請求需要注意的地方:

  • 需要在AndroidManifest中新增訪問網路的許可權
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
  • 需要開啟子執行緒訪問網路
new Thread(new Runnable
    {
        //access the Internet
    }).start();

HttpURLConnection實現POST請求

當需要向server寫資料時,就需要使用post請求。Http請求由三部分組成,分別是:請求頭、訊息報頭(可選)、請求正文
Http響應也是由三個部分組成,分別是:響應頭、訊息報頭(可選)、響應正文

其中請求頭允許客戶端傳遞關於自身的資訊和希望的響應形式,它負責通知伺服器有關客戶端請求的資訊,下表列出了http的請求頭,其中用黃色標記的請求頭較為常用:
這裡寫圖片描述
這裡寫圖片描述

與請求頭對應,響應頭域允許伺服器傳遞不能放在狀態行的附加資訊,下表列出了http的響應頭,其中用黃色標記的響應頭較為常用:
這裡寫圖片描述
這裡寫圖片描述

HttpURLConnection實現post請求步驟如下:

  1. 設定無引數的server訪問地址、方法;
  2. 建立URL物件,將上述訪問地址傳入;
  3. 呼叫URL.openConnection()方法返回HttpURLConnection物件;
  4. 呼叫HttpURLConnection.connect()方法連線server;
  5. 呼叫HttpURLConnection類中的setDoInput() [設定輸入流]、setDoOutput() [設定輸出流]、setRequestMethod() [設定請求型別]、setUseCaches() [設定是否使用快取]、setRequestProperty() [設定響應頭];
  6. 呼叫HttpURLConnection.getOutputStream()方法向server傳送資訊;
  7. 呼叫HttpURLConnection.connect()方法連線server;
  8. 呼叫HttpURLConnection.getInputStream()方法讀取server返回的內容;
  9. 關閉流、呼叫HttpURLConnection.disconnect()方法斷開連線。

由此看出,相比於get方式,post方式不允許將引數值出入URL物件,而是需要呼叫HttpURLConnection.getOutputStream()方法專門向server傳送引數資訊;另外,需要呼叫HttpURLConnection的方法設定輸入輸出流、響應頭等操作。

新增一個按鈕用於測試post請求:
這裡寫圖片描述

下面是post請求的程式碼示例:

//doPost請求
    private void doPost(final String s) {
        //post請求的URL沒有請求引數
        final String postAddress = mUrl + mMethod;

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(postAddress);
                    HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
                    //開啟HttpURLConnection的輸入輸出
                    httpUrlConnection.setDoInput(true);
                    httpUrlConnection.setDoOutput(true);
                    //設定請求為post請求
                    httpUrlConnection.setRequestMethod("POST");
                    //不使用快取
                    httpUrlConnection.setUseCaches(false);
                    //設定請求頭
                    //設定編碼集
                    httpUrlConnection.setRequestProperty("Accept-Charset", "UTF-8");
                    //設定content-type
                    httpUrlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                    //連線server
                    httpUrlConnection.connect();
                    //將需要傳送的引數資訊寫給server
                    OutputStream os = httpUrlConnection.getOutputStream();
                    //包裝流:資料輸出流(字元處理流)
                    DataOutputStream dos = new DataOutputStream(os);
                    String content = "sex" + s;

                    dos.writeBytes(content);
                    os.flush();
                    os.close();
                    dos.flush();
                    dos.close();

                    //獲得server返回資料
                    if (httpUrlConnection.getResponseCode() == 200) {
                        InputStream is = httpUrlConnection.getInputStream();
                        BufferedReader br = new BufferedReader(new InputStreamReader(is));
                        StringBuffer sb = new StringBuffer();
                        String readLine = "";
                        while ((readLine = br.readLine()) != null) {
                            sb.append(readLine);

                        }
                        is.close();
                        br.close();
                        httpUrlConnection.disconnect();
                        Log.i("POST_TAG", sb.toString());

                    } else {
                        Log.i("POST_TAG", "failed!");
                    }


                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }).start();


    }

點選在LogCat中的顯示如下:
這裡寫圖片描述

Get請求和Post請求的區別

上面介紹了使用HttpURLConnection類實現Get請求和Post請求,下面簡要介紹它們的區別:

  1. get是從伺服器上獲取資料,post是向伺服器傳送資料。
  2. get是把引數資料佇列tian新增到指定的URL中,引數值和引數名各個欄位一一對應,並且在URL中可以看到。post是通過HTTPpost機制,將請求的引數名和引數值放置在HTML HEADER內一起傳送到指定的URL地址。使用者看不到這個過程。
  3. 對於get方式,伺服器端用 Request.QueryString獲取變數的值,對於post方式,伺服器端用Request.Form獲取提交的資料。
  4. get 傳送的資料量較小,不能大於2KB。post傳送的資料量較大,一般被預設為不受限制。但理論上,IIS4中最大量為80KB,IIS5中為100KB。
  5. get安全性非常低,post安全性較高。

廢棄HttpClient類

在較低的Android API版本中,通過Org.apache.HttpClient,Android也能訪問網路,但在4.x及後續版本已不被推薦使用,更是在Android 6.0 (API 23)中被廢棄,很大一部分原因就是HttpClient類的封裝性很高,導致其擴充套件性不如HttpURLConnection。當然,如今HttpURLConnection類也被封裝的很好,OkHttp就是將其封裝得很好且擴充套件性更高的一個框架,下面將對OkHttp做簡單介紹。

使用OkHttp訪問網路

HttpURLConnection和HttpClient,雖然兩者都能滿足HTTPS流的上傳和下載,配置超時,IPv6和連線池等各種HTTP請求的需求,但更高效的使用HTTP可以讓我們的應用執行更快、更節省流量。而OkHttp庫就是為此而生。
OkHttp是一個高效的HTTP庫:
1、支援 SPDY ,共享同一個Socket來處理同一個伺服器的所有請求,如果SPDY不可用,則通過連線池來減少請求延時。
2、無縫的支援GZIP來減少資料流量
3、快取響應資料來減少重複的網路請求:會從很多常用的連線問題中自動恢復。如果伺服器配置了多個IP地址,當第一個IP連線失敗的時候,OkHttp會自動嘗試下一個IP。OkHttp還處理了代理伺服器問題和SSL握手失敗問題。
4、使用 OkHttp 無需重寫程式中的網路程式碼。OkHttp實現了幾乎和HttpURLConnection一樣的API。如果用了HttpClient,則OkHttp也提供了一個對應的okhttp-apache 模組。
5、OkHttp是一個相對成熟的解決方案,Android4.4的原始碼中已經將HttpURLConnection替換成了OkHttp。

使用OkHttp傳送GET請求

為了在程式中使用OkHttp框架,需要在gradle中新增依賴:

compile 'com.squareup.okhttp3:okhttp:3.2.0'

在佈局中新增兩個按鈕,用於傳送Get請求和Post請求。
這裡寫圖片描述
以下是Get請求的程式碼示例:

private void doGet(String s) {
//拼接訪問server地址
        final String address = new StringBuilder().append(mUrl).append(mMethod).append("?sex=").append(s).toString();
        new Thread(new Runnable() {
            @Override
            public void run() {
            //建立okhttp3.Request物件,傳入訪問地址
                Request request = new Request.Builder().url(address).build();
                try {
                //使用同步方式獲得返回物件okhttp3.Response
                    Response response = mOkHttpCLient.newCall(request).execute();
                    //訪問成功
                    if (response.isSuccessful()) {
                        //呼叫Response.body().string()方法獲得server返回的結果
                        Log.i("TAG", response.body().string());
                    } else {
                        Log.i("TAG", "error!");

                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }).start();


    }

使用OkHttp傳送POST請求

/**
     * @param s post的請求引數
     */
    private void doPost(String s) {
    //建立FormBody物件,用於封裝post的請求引數
        FormBody formBody = new FormBody.Builder().add("sex", s).build();
        //建立Request物件,用於封裝URL請求地址及請求引數
        Request request = new Request.Builder().url(new StringBuilder().append(mUrl).append(mMethod).toString()).post(formBody).build();

        //採用非同步方式回撥server返回的結果
        mOkHttpCLient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i("TAG", "failed");
            }

            //該回調方法的返回引數Response就是server的返回結果
            @Override
            public void onResponse(Call call, Response response) throws IOException {

                //輸出結果
                Log.i("TAG", response.body().string());

            }
        });

    }

這裡寫圖片描述

有關OkHttp的更多學習資料,請您訪問:

解析JSON格式資料

JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式。它基於ECMAScript的一個子集。 JSON採用完全獨立於語言的文字格式,但是也使用了類似於C語言家族的習慣(包括C、C++、C#、Java、JavaScript、Perl、Python等)。這些特性使JSON成為理想的資料交換語言。 易於人閱讀和編寫,同時也易於機器解析和生成(一般用於提升網路傳輸速率)。

JSON資料的語法規則

JSON 語法規則:
1、資料在鍵值對中
2、資料由逗號分隔
3、花括號儲存物件
4、方括號儲存陣列

JSON 值可以是:
1、數字(整數或浮點數)
2、字串(在雙引號中)
3、邏輯值(true 或 false)
4、陣列(在方括號中)
5、物件(在花括號中)
6、null

JSON格式資料的優缺點

優點:
1、資料格式比較簡單,易於讀寫,格式都是壓縮的,佔用頻寬小;
2、易於解析,客戶端JavaScript可以簡單的通過eval()進行JSON資料的讀取;
3、支援多種語言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等伺服器端語言,便於伺服器端的解析;
4、在PHP世界,已經有PHP-JSON和JSON-PHP出現了,偏於PHP序列化後的程式直接呼叫,PHP伺服器端的物件、陣列等能直接生成JSON格式,便於客戶端的訪問提取;
5、因為JSON格式能直接為伺服器端程式碼使用,大大簡化了伺服器端和客戶端的程式碼開發量,且完成任務不變,並且易於維護。

缺點:
1、沒有XML格式這麼推廣的深入人心和喜用廣泛,沒有XML那麼通用性;
2、JSON格式目前在Web Service中推廣還屬於初級階段。

解析JSON資料

下面提供了一段JSON格式的資料:
這裡寫圖片描述

下面程式碼將解析上述JSON資料:

/**
     * @param json
     */
    private void parseData(String json) {


        JSONObject objectOutside = null;
        try {
            objectOutside = new JSONObject(json);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        try {
            String country = objectOutside.getString("name");
            Log.i("TAG", "Country: " + country);
            JSONArray provinces = objectOutside.getJSONArray("provinces");


            for (int i = 0; i < provinces.length(); ++i) {
                JSONObject objectInside = provinces.getJSONObject(i);
                String province = objectInside.getString("name");

                Log.i("TAG", "Province " + (i + 1) + ": " + province);
                JSONObject objectCities = objectInside.getJSONObject("citys");
                JSONArray arrayCity = objectCities.getJSONArray("city");

                StringBuffer sb = new StringBuffer();
                for (int j = 0; j < arrayCity.length(); ++j) {
                    String city = arrayCity.getString(j);
                    sb.append("City " + (j + 1) + ": " + city + "     ");


                }

                Log.i("TAG", sb.toString());


            }


        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

解析結果如下所示:
這裡寫圖片描述

解析XML格式資料

XML是一種可擴充套件標記語言:
1、可擴充套件標記語言是一種很像超文字標記語言的標記語言。
2、它的設計宗旨是傳輸資料,而不是顯示資料。
3、它的標籤沒有被預定義。您需要自行定義標籤。
4、它被設計為具有自我描述性。
5、它是W3C的推薦標準。

可擴充套件標記語言(XML)和超文字標記語言(HTML)之間的差異:
1、它不是超文字標記語言的替代。
2、它是對超文字標記語言的補充。
3、它和超文字標記語言為不同的目的而設計:
4、它被設計用來傳輸和儲存資料,其焦點是資料的內容。
5、超文字標記語言被設計用來顯示資料,其焦點是資料的外觀。

超文字標記語言(XML)存在的問題:
1、某些起始標籤可以選擇性出現結束標籤或者隱含了結束標籤。
2、標籤可以以任何順序巢狀,即使結束標籤不按照起始標籤的逆序出現也是允許的。
3、某些特性不要求一定有值。
4、定義特性的兩邊有沒有加上雙引號都是可以的,所以都是允許的。

可擴充套件標記語言如何解決問題:
1、任何的起始標籤都必須有一個結束標籤。
2、可以採用另一種簡化語法,可以在一個標籤中同時表示起始和結束標籤。
3、標籤必須按合適的順序進行巢狀,所以結束標籤必須按映象順序匹配起始標籤。
4、所有的特性都必須有值。
5、所有的特性都必須在值的周圍加上雙引號。

XML格式資料的優缺點

XML的優點:
1、格式統一,符合標準;
2、容易與其他系統進行遠端互動,資料共享比較方便。

XML的缺點:
1、XML檔案龐大,檔案格式複雜,傳輸佔頻寬;
2、伺服器端和客戶端都需要花費大量程式碼來解析XML,導致伺服器端和客戶端程式碼變得異常複雜且不易維護;
3、客戶端不同瀏覽器之間解析XML的方式不一致,需要重複編寫很多程式碼;
4、伺服器端和客戶端解析XML花費較多的資源和時間。

解析XML格式資料

下限是一段XML格式的資料:

<?xml version="1.0" encoding="gb2312"?> 
<root> 
    <item> 
        <name>劉亦菲</name> 
        <url>MingXing/LiuYiFei.htm</url> 
        <color>red</color> 
    </item> 
    <item> 
        <name>蔡依林</name> 
        <url>MingXing/CaiYiLin.htm</url> 
        <color>blue</color> 
    </item> 
    <item> 
        <name>張娜拉</name> 
        <url>MingXing/ZhangNaLa.htm</url> 
        <color>green</color> 
    </item> 
    <item> 
        <name>張韶涵</name> 
        <url>MingXiang/ZhangShaoHan.htm</url> 
        <color>grey</color> 
    </item> 
    <item> 
        <name>張靚穎</name> 
        <url>MingXing/ZhangLiangYin.htm</url> 
        <color>black</color> 
    </item> 
    <item> 
        <name>李宇春</name> 
        <url>MingXing/LiYuChun.htm</url> 
        <color>yellow</color> 
    </item> 
    <item> 
        <name>徐若瑄</name> 
        <url>MingXing/XuLuXuan.htm</url> 
        <color>pink</color> 
    </item> 
</root>

下面使用PULL解析方式對上述XML格式資料進行解析:

/**
     * @param mXML2
     */
    private void parseXML2(String mXML2) {
        List<Star> list = null;
        Star star = null;

        //XMLPullParser.setInput()方法接收InputStream型別,故首先將String型別的XML資料轉換成InputStream型別
        InputStream is = new ByteArrayInputStream(mXML2.getBytes());
        XmlPullParser xpp = Xml.newPullParser();
        try {
            //XMLPullParser.setInput()方法接收InputStream型別
            xpp.setInput(is, "UTF-8");
            //獲取標籤型別
            int type = xpp.getEventType();
            //若未讀到最後的結束標籤,則不停遍歷每個標籤及其內容
            while (type != XmlPullParser.END_DOCUMENT) {
                switch (type) {

                    //若為XML檔案起始標籤,則例項化List物件
                    case XmlPullParser.START_DOCUMENT:
                        list = new ArrayList<>();
                        break;
                    //若讀到每項的起始標籤
                    case XmlPullParser.START_TAG:
                        //起始標籤為"item"
                        if ("item".equals(xpp.getName())) {
                            //例項化Star物件
                            star = new Star();

                        }
                        // 起始標籤為"name"
                        else if ("name".equals(xpp.getName())) {
                            //後移一項
                            xpp.next();
                            //此時指向"name"標籤的內容,將該內容設定到建立的Star物件中
                            star.setName(xpp.getText());
                        } 
                        //起始標籤為"url"
                        else if ("url".equals(xpp.getName())) {
                            //後移一項
                            xpp.next();
                            //此時指向"url"標籤的內容,將該內容設定到建立的Star物件中
                            star.setUrl(xpp.getText());

                        } 
                        //起始標籤為"color"
                        else if ("color".equals(xpp.getName())) {
                            //後移一項
                            xpp.next();
                            //此時指向"color"標籤的內容,將該內容設定到建立的Star物件中
                            star.setColor(xpp.getText());
                        }
                        break;
                    //若指向結束標籤
                    case XmlPullParser.END_TAG:
                        //結束標籤為"item"時,說明已讀完一個完整的Star物件,該Star的所有欄位已被賦值物件
                        if ("item".equals(xpp.getName())) {

                            //將該Star物件加入List集合中
                            list.add(star);
                        }
                        break;
                    default:
                        break;
                }

                //後移一項
                type = xpp.next();

            }
            //在LogCat中列印結果
            for (Star s : list) {
                Log.i("XML2", s.toString());
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

在LogCat中的輸出結果如下所示:
這裡寫圖片描述