精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

在Android應用程序中使用Internet數(shù)據(jù)

移動開發(fā) Android
您的很多 Android 應用程序都需要與 Internet 數(shù)據(jù)交互,這些數(shù)據(jù)采用各種格式。本文將帶您構建一個 Android 應用程序,它可以使用兩種流行數(shù)據(jù)格式 —XML 和 JavaScript Object Notation (JSON)— 以及來自 Google 的比較奇異的 protocol buffers 格式。您將了解到與每個格式相關的性能和編碼利弊。

Android 應用程序必須訪問位于 Internet 上的數(shù)據(jù),而 Internet 數(shù)據(jù)可以有幾種不同的格式。本文將介紹在 Android 應用程序中如何使用三種數(shù)據(jù)格式:

XML

JSON 首先開發(fā)一個 Web 服務,將 CSV 數(shù)據(jù)轉(zhuǎn)換成 XML、JSON 和 protocol-buffers 格式。然后構建一個樣例 Android 應用程序,可以從 Web 服務中以任何一種格式提取數(shù)據(jù)并將其解析并顯示給用戶。

Google 的 protocol buffers

要進行本文中的練習,您需要最新的 Android SDK(參見 參考資料)和 Android 2.2 平臺。SDK 還要求您安裝一個 Java™ 開發(fā)包(JDK);本文中使用了 JDK 1.6.0_17。您不需要有 Android 物理設備;所有代碼都將在 SDK 的 Android 仿真器中運行。本文并沒有教您如何進行 Android 開發(fā),因此建議您熟悉 Android 編程。當然,只憑借 Java 編程語言的知識也可以完成本文的學習。

您還需要一個 Java web 應用程序服務器來運行 Android 應用程序使用的 Web 服務。此外,也可以將服務器端代碼部署到 Google App Engine。參見 下載 部分獲得完整的源代碼。

Day Trader 應用程序

您將開發(fā)一個簡單的 Android 應用程序,叫做 Day Trader。Day Trader 允許用戶輸入一個或更多的股票代碼并獲取其所代表股票的最新價格信息。用戶可以指定數(shù)據(jù)使用的格式:XML、JSON 或 protocol buffers。實際的 Android 應用程序通常不會提供此選擇,但是通過實現(xiàn)此功能,您可以了解如何讓您的應用程序處理每一種格式。圖 1 展示了 Day Trader 用戶界面:

圖 1. 運行中的 Day Trader 應用程序

文本框及其旁邊的 Add Stock 按鈕允許用戶輸入感興趣的每支股票的代碼。用戶按下 Download Stock Data 按鈕后,會從服務器請求所有這些股票的數(shù)據(jù),在應用程序中解析并顯示在屏幕上。默認情況下,獲取的是 XML 數(shù)據(jù)。通過菜單,您可以在 XML、JSON 或 protocol buffers 數(shù)據(jù)格式間切換。

清單1顯示用于創(chuàng)建 圖 1 中所示 UI 的布局 XML:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical" 
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     > 
  7.     <LinearLayout android:orientation="horizontal"   
  8.         android:layout_width="fill_parent"   
  9.         android:layout_height="wrap_content"> 
  10.         <EditText android:id="@+id/symbol" android:layout_width="wrap_content" 
  11.             android:layout_height="wrap_content" android:width="120dip"/> 
  12.         <Button android:id="@+id/addBtn" android:layout_width="wrap_content" 
  13.             android:layout_height="wrap_content"   
  14.             android:text="@string/addBtnLbl"/> 
  15.     </LinearLayout> 
  16.     <LinearLayout android:orientation="horizontal"   
  17.         android:layout_width="fill_parent"   
  18.         android:layout_height="wrap_content"> 
  19.         <TextView android:layout_width="wrap_content"   
  20.             android:layout_height="wrap_content" android:id="@+id/symList" /> 
  21.         <Button android:id="@+id/dlBtn" android:layout_width="wrap_content"   
  22.             android:layout_height="wrap_content"   
  23.             android:text="@string/dlBtnLbl" 
  24.         /> 
  25.        </LinearLayout> 
  26.     <ListView android:id="@android:id/list"   
  27.         android:layout_height="fill_parent" android:layout_width="fill_parent" 
  28.         android:layout_weight="1" 
  29.         /> 
  30. </LinearLayout> 

上述中的大部分代碼都簡單明了。可以看到幾個小部件創(chuàng)建了 圖 1 所示的輸入和按鈕。還會看到一個 ListView,Android 小部件中真正的瑞士軍刀。此 ListView 將用從服務器下載的股票數(shù)據(jù)填充。清單 2 顯示了控制該視圖的 Activity:

清單 2. Day Trader 主活動


  1. public class Main extends ListActivity {  
  2.     private int mode = XML; // default  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.main);  
  7.         final EditText input = (EditText) findViewById(R.id.symbol);  
  8.         final TextView symbolsList = (TextView) findViewById(R.id.symList);  
  9.         final Button addButton = (Button) findViewById(R.id.addBtn);  
  10.         final Button dlButton = (Button) findViewById(R.id.dlBtn);  
  11.         addButton.setOnClickListener(new OnClickListener(){  
  12.             public void onClick(View v) {  
  13.                 String newSymbol = input.getText().toString();  
  14.                 if (symbolsList.getText() == null ||   
  15.                         symbolsList.getText().length() == 0){  
  16.                     symbolsList.setText(newSymbol);  
  17.                 } else {  
  18.                     StringBuilder sb =   
  19.                                   new StringBuilder(symbolsList.getText());  
  20.                     sb.append(",");  
  21.                     sb.append(newSymbol);  
  22.                     symbolsList.setText(sb.toString());  
  23.                 }  
  24.                 input.setText("");  
  25.             }  
  26.         });  
  27.         dlButton.setOnClickListener(new OnClickListener(){  
  28.             public void onClick(View v) {  
  29.                 String symList = symbolsList.getText().toString();  
  30.                 String[] symbols = symList.split(",");  
  31.                 symbolsList.setText("");  
  32.                 switch (mode){  
  33.                 case JSON :  
  34.                     new StockJsonParser().execute(symbols);  
  35.                     break;  
  36.                 case PROTOBUF :  
  37.                     new StockProtoBufParser().execute(symbols);  
  38.                     break;  
  39.                 default :  
  40.                     new StockXmlParser().execute(symbols);  
  41.                     break;  
  42.                 }  
  43.             }  
  44.         }  
  45.     }  

此 Activity 設置了 清單 1 中 XML 文件的布局,它將幾個事件處理程序連接起來。首先,對于 Add Stock 按鈕而言,代碼讀取文本框中的代碼并將其添加到 symList TextView 中,用逗號分隔每個代碼。接下來,對于 Download 按鈕而言,處理程序從 symList TextView 中讀取數(shù)據(jù),然后 —基于 mode 變量— 使用三個不同的類之一從服務器下載數(shù)據(jù)。菜單設置 mode 變量的值;這個代碼不是很重要,因此我在 清單 2 中省略了它。在了解各種數(shù)據(jù)下載/解析類之前,我先為您展示一下服務器如何提供此數(shù)據(jù)。提供股票數(shù)據(jù)

應用程序服務器需要能夠做兩件事。第一,它必須獲取股票代碼列表并檢索它們的數(shù)據(jù)。然后,它需要接受一個格式參數(shù)并基于該格式編碼數(shù)據(jù)。對于 XML 和 JSON 格式而言,該服務器將返回作為文本的串行化的股票數(shù)據(jù)。對于 protocol buffers 而言,它必須發(fā)送二進制數(shù)據(jù)。 清單 3 顯示了處理這些步驟的 servlet:

#p#

清單 3. Stock Broker servlet    

  1. public class StockBrokerServlet extends HttpServlet {  
  2.     public void doGet(HttpServletRequest request,   
  3.           HttpServletResponse response) throws IOException {  
  4.         String[] symbols = request.getParameterValues("stock");  
  5.         List<Stock> stocks = getStocks(symbols);  
  6.         String format = request.getParameter("format");  
  7.         String data = "";  
  8.         if (format == null || format.equalsIgnoreCase("xml")){  
  9.             data = Stock.toXml(stocks);  
  10.             response.setContentType("text/xml");      
  11.         } else if (format.equalsIgnoreCase("json")){  
  12.             data = Stock.toJson(stocks);  
  13.             response.setContentType("application/json");  
  14.         } else if (format.equalsIgnoreCase("protobuf")){  
  15.             Portfolio p = Stock.toProtoBuf(stocks);  
  16.             response.setContentType("application/octet-stream");  
  17.             response.setContentLength(p.getSerializedSize());  
  18.             p.writeTo(response.getOutputStream());  
  19.             response.flushBuffer();  
  20.             return;  
  21.         }  
  22.         response.setContentLength(data.length());  
  23.         response.getWriter().print(data);  
  24.         response.flushBuffer();  
  25.         response.getWriter().close();  
  26.     }  
  27.  
  28.     public List<Stock> getStocks(String... symbols) throws IOException{  
  29.         StringBuilder sb = new StringBuilder();  
  30.         for (String symbol : symbols){  
  31.             sb.append(symbol);  
  32.             sb.append('+');  
  33.         }  
  34.         sb.deleteCharAt(sb.length() - 1);  
  35.         String urlStr =   
  36.                 "http://finance.yahoo.com/d/quotes.csv?f=sb2n&s=" +   
  37.                     sb.toString();  
  38.         URL url = new URL(urlStr);  
  39.         HttpURLConnection conn =   
  40.                 (HttpURLConnection) url.openConnection();  
  41.         BufferedReader reader = new BufferedReader(  
  42.                 new InputStreamReader(conn.getInputStream()));  
  43.         String quote = reader.readLine();  
  44.         List<Stock> stocks = new ArrayList<Stock>(symbols.length);  
  45.         while (quote != null){  
  46.             String[] values = quote.split(",");  
  47.             Stock s =   
  48.                       new Stock(values[0], values[2],  
  49.                            Double.parseDouble(values[1]));  
  50.             stocks.add(s);  
  51.             quote = reader.readLine();  
  52.         }  
  53.         return stocks;  
  54.     }  

這是一個簡單的 Java servlet,只支持 HTTP GET 請求。它讀入股票的值和格式請求參數(shù)。然后調(diào)用 getStocks() 方法。該方法調(diào)用 Yahoo! Finance 獲取股票數(shù)據(jù)。Yahoo! 只支持 CSV 格式的數(shù)據(jù),因此 getStocks() 方法將其解析到一個 Stock 對象列表。清單 4 展示了這個簡單的數(shù)據(jù)結(jié)構:

清單 4. 股票數(shù)據(jù)結(jié)構

  1. public class Stock {      
  2.     private final String symbol;  
  3.     private final String name;  
  4.     private final double price;  
  5.       //getters and setters omitted  
  6.     public String toXml(){  
  7.         return "<stock><symbol>" + symbol +   
  8. "</symbol><name><![CDATA[" +  
  9.             name + "]]></name><price>" + price +   
  10. "</price></stock>";  
  11.     }  
  12.     public String toJson(){  
  13.         return "{ 'stock' : { 'symbol' : " +symbol +", 'name':" + name +   
  14.             ", 'price': '" + price + "'}}";  
  15.     }  
  16.     public static String toXml(List<Stock> stocks){  
  17.         StringBuilder xml = new StringBuilder("<stocks>");  
  18.         for (Stock s : stocks){  
  19.             xml.append(s.toXml());  
  20.         }  
  21.         xml.append("</stocks>");  
  22.         return xml.toString();  
  23.     }  
  24.     public static String toJson(List<Stock> stocks){  
  25.         StringBuilder json = new StringBuilder("{'stocks' : [");  
  26.         for (Stock s : stocks){  
  27.             json.append(s.toJson());  
  28.             json.append(',');  
  29.         }  
  30.         json.deleteCharAt(json.length() - 1);  
  31.         json.append("]}");  
  32.         return json.toString();  
  33.     }  

每個 Stock 都有三個屬性— symbol、name 和 price — 和幾個便捷的方法,以便將其自己轉(zhuǎn)換成 XML 字符串或 JSON 字符串。它提供了一個工具方法,用于將 Stock 對象列表轉(zhuǎn)換成 XML 或 JSON。回到 清單 3,根據(jù)格式請求參數(shù),Stock 對象列表被轉(zhuǎn)換成 XML 或 JSON 字符串并被發(fā)送回客戶端。

XML 和 JSON 用例非常類似和直接。對于 protocol buffers,您必須生成 protocol buffers 格式的代碼讀寫對象。為此,您需要使用 protocol buffers 規(guī)范格式定義數(shù)據(jù)結(jié)構。清單 5 展示了一個示例:

#p#

清單 5. 股票的 Protocol buffers 消息

  1. package stocks;  
  2. option java_package = "org.developerworks.stocks";  
  3. message Quote{  
  4.     required string symbol = 1;  
  5.     required string name = 2;  
  6.     required double price = 3;  
  7. }  
  8. message Portfolio{  
  9.     repeated Quote quote = 1;  

protocol buffers 消息格式類似于接口描述語言 (IDL),它與語言無關,因此可以將其與各種語言一起使用。在本例中,運行 protocol buffers 編譯器(protoc)將 清單 5 中的代碼編譯成要用于客戶端和服務器的 Java 類。有關將 protocol buffers 消息編譯成 Java 類的詳細信息,請參閱 Protocol Buffers Developer Guide(參見 參考資料)。

在 清單 3 中,一個名為 toProtoBuf() 的方法將 Stock 對象列表轉(zhuǎn)換成一個 Portfolio 消息。清單 6 展示了該方法的實現(xiàn):

清單 6. 創(chuàng)建組合消息    

  1. public static Stocks.Portfolio toProtoBuf(List<Stock> stocks){  
  2.     List<Stocks.Quote> quotes = new ArrayList<Stocks.Quote>(stocks.size());  
  3.     for (Stock s : stocks){  
  4.         Quote q =   
  5.             Quote.newBuilder()  
  6.                 .setName(s.name)  
  7.                 .setSymbol(s.symbol)  
  8.                 .setPrice(s.price)  
  9.                 .build();  
  10.         quotes.add(q);  
  11.     }  
  12.     return Portfolio.newBuilder().addAllQuote(quotes).build();  

清單 6 中的代碼使用了從 清單 5 中的消息生成的代碼 — Quote 和 Portfolio 類。只需構建來自每個 Stock 對象的 Quote,然后將其添加到 清單 3 中返回到 servlet 的 Portfolio 對象即可。在 清單 3 中,servlet 直接打開到客戶端的流并使用生成的代碼編寫到流的二進制協(xié)議 buffers 數(shù)據(jù)。

現(xiàn)在,您了解了服務器如何創(chuàng)建要發(fā)送到 Android 應用程序的數(shù)據(jù)。接下來將學習應用程序如何解析此數(shù)據(jù)。

清單 2 中的主 Activity 需要使用服務器可以發(fā)送的各種格式的數(shù)據(jù)。它還需要請求適當格式的數(shù)據(jù)并且數(shù)據(jù)一旦解析,就用它來填充其 ListView。因此,無論數(shù)據(jù)格式是什么,大部分功能都是通用的。

首先,創(chuàng)建一個抽象的基類,封裝此通用功能,如 清單 7 所示:

清單 7. 數(shù)據(jù)解析器基類   

  1. abstract class BaseStockParser extends AsyncTask<String, Integer, Stock[]>{  
  2.     String urlStr = "http://protostocks.appspot.com/stockbroker?format=";  
  3.     protected BaseStockParser(String format){  
  4.         urlStr += format;  
  5.     }  
  6.     private String makeUrlString(String... symbols) {  
  7.         StringBuilder sb = new StringBuilder(urlStr);  
  8.         for (int i=0;i<symbols.length;i++){  
  9.             sb.append("&stock=");  
  10.             sb.append(symbols[i]);  
  11.         }  
  12.         return sb.toString();  
  13.     }  
  14.     protected InputStream getData(String[] symbols) throws Exception{  
  15.         HttpClient client = new DefaultHttpClient();  
  16.         HttpGet request = new HttpGet(new URI(makeUrlString(symbols)));  
  17.  
  18.         HttpResponse response = client.execute(request);  
  19.         return response.getEntity().getContent();  
  20.     }  
  21.     @Override  
  22.     protected void onPostExecute(Stock[] stocks){  
  23.         ArrayAdapter<Stock> adapter =   
  24.             new ArrayAdapter<Stock>(Main.this, R.layout.stock,   
  25.                       stocks );  
  26.         setListAdapter(adapter);  
  27.     }  

清單 7 中的基類擴展了 android.os.AsyncTask。這是一個常用的用于異步操作的類。它抽象出線程和處理程序的創(chuàng)建,用于請求主 UI 線程。它是基于其輸入和輸出數(shù)據(jù)類型參數(shù)化的。對于所有解析器而言,輸入總是一樣的:股票代碼字符串。 輸出也是一樣的:Stock 對象數(shù)組。基類獲取 format,這是一個指定了要使用的數(shù)據(jù)格式的字符串。然后提供一個方法,發(fā)出適當?shù)?HTTP 請求并返回一個流響應。最后,它覆蓋 AsyncTask 的 onPostExecute() 方法并使用從解析器返回的數(shù)據(jù)為 Activity 的 ListView 創(chuàng)建一個 Adapter。

現(xiàn)在看到三個解析器的功能是通用的。我將為您展示更具體的解析代碼,從 XML 解析器開始。

#p#

用 SAX 解析 XML

Android SDK 提供了幾種使用 XML 的方式,包括標準 DOM 和 SAX。 對于一些對內(nèi)存密集型情況,可以使用 SDK 的 pull-parser。大部分時候,SAX 是最快的方式。Android 包括一些便捷的 API 使得使用 SAX 更輕松。清單 8 顯示了 Day Trader 應用程序的 XML 解析器

清單 8. XML 解析器實現(xiàn)

  1. private class StockXmlParser extends BaseStockParser{  
  2.     public StockXmlParser(){  
  3.         super("xml");  
  4.     }  
  5.     @Override  
  6.     protected Stock[] doInBackground(String... symbols) {  
  7.         ArrayList<Stock> stocks = new ArrayList<Stock>(symbols.length);  
  8.         try{  
  9.             ContentHandler handler = newHandler(stocks);  
  10.             Xml.parse(getData(symbols), Xml.Encoding.UTF_8, handler);  
  11.         } catch (Exception e){  
  12.             Log.e("DayTrader", "Exception getting XML data", e);  
  13.         }  
  14.         Stock[] array = new Stock[symbols.length];  
  15.         return stocks.toArray(array);  
  16.     }  
  17.     private ContentHandler newHandler(final ArrayList<Stock> stocks){  
  18.         RootElement root = new RootElement("stocks");  
  19.         Element stock = root.getChild("stock");  
  20.         final Stock currentStock = new Stock();  
  21.         stock.setEndElementListener(  
  22.             new EndElementListener(){  
  23.                 public void end() {  
  24.                     stocks.add((Stock) currentStock.clone());  
  25.                 }  
  26.             }  
  27.         );  
  28.         stock.getChild("name").setEndTextElementListener(  
  29.             new EndTextElementListener(){  
  30.                 public void end(String body) {  
  31.                     currentStock.setName(body);  
  32.                 }  
  33.             }  
  34.         );  
  35.         stock.getChild("symbol").setEndTextElementListener(  
  36.             new EndTextElementListener(){  
  37.                 public void end(String body) {  
  38.                     currentStock.setSymbol(body);  
  39.                 }  
  40.             }  
  41.         );  
  42.         stock.getChild("price").setEndTextElementListener(  
  43.             new EndTextElementListener(){  
  44.                 public void end(String body) {  
  45.                             currentStock.setPrice(Double.parseDouble(body));  
  46.                 }  
  47.             }  
  48.         );  
  49.         return root.getContentHandler();  
  50.     }  

清單 8 中的大部分代碼都在 newHandler() 方法中,該方法創(chuàng)建一個 ContentHandler。如果熟悉 SAX 解析, 會知道 ContentHandler 通過響應 SAX 解析器觸發(fā)的各種事件創(chuàng)建解析數(shù)據(jù)。newHandler() 方法使用 Android 便捷 API 指定使用事件處理程序的 ContentHandler。代碼只是偵聽在解析器遇到各種標記時觸發(fā)的事件,然后選取數(shù)據(jù),放到 Stock 對象列表中。 創(chuàng)建 ContentHandler 后,調(diào)用 Xml.parse() 方法來解析基類提供的 InputStream 并返回 Stock 對象數(shù)組。這是快速解析 XML 的方法,但是 —即使使用 Android 提供的便捷 API— 它也是非常冗長的。

使用 JSON

XML 是 Android 上的一等公民,鑒于依賴于 XML 的 Web 服務的數(shù)量,這是個好事。很多服務還支持另一個流行格式 JSON。它通常比 XML 簡潔一些,但也是人們可讀的,使得它更易于使用,并且可以更輕松地將其用于調(diào)試使用它的應用程序。Android 包括一個 JSON 解析器。(您可以從 JSON.org 網(wǎng)站獲得該解析器,只是要去除幾個手機不需要的類)。 清單 9 顯示了使用中的解析器:

清單 9. JSON 解析器實現(xiàn)    

  1. private class StockJsonParser extends BaseStockParser{  
  2.     public StockJsonParser(){  
  3.         super("json");  
  4.     }  
  5.     @Override  
  6.     protected Stock[] doInBackground(String... symbols) {  
  7.         Stock[] stocks = new Stock[symbols.length];  
  8.         try{  
  9.             StringBuilder json = new StringBuilder();  
  10.             BufferedReader reader =   
  11.                 new BufferedReader(  
  12.                             new InputStreamReader(getData(symbols)));  
  13.             String line = reader.readLine();  
  14.             while (line != null){  
  15.                 json.append(line);  
  16.                 line = reader.readLine();  
  17.             }  
  18.             JSONObject jsonObj = new JSONObject(json.toString());  
  19.             JSONArray stockArray = jsonObj.getJSONArray("stocks");  
  20.             for (int i=0;i<stocks.length;i++){  
  21.                 JSONObject object =   
  22.                     stockArray.getJSONObject(i).getJSONObject("stock");  
  23.                 stocks[i] = new Stock(object.getString("symbol"),   
  24.                         object.getString("name"),   
  25.                         object.getDouble("price"));  
  26.             }  
  27.         } catch (Exception e){  
  28.             Log.e("DayTrader", "Exception getting JSON data", e);  
  29.         }  
  30.         return stocks;  
  31.     }  

可以看到在 Android 中使用 JSON 解析器是多么簡單。您將來自服務器的流轉(zhuǎn)換成傳遞給 JSON 解析器的字符串。您遍歷對象圖并創(chuàng)建 Stock 對象數(shù)組。如果使用過 XML DOM 解析,這看起來很類似,因為編程模型幾乎一樣。

像 DOM 一樣,JSON 解析器可以用于內(nèi)存密集型應用。在 清單 9 中,所有來自服務器的數(shù)據(jù)都表示為字符串,然后作為 JSONObject,最后作為 Stock 對象數(shù)組。換句話說,同一數(shù)據(jù)通過三種不同的方式表示。可以看到,對于大量數(shù)據(jù)而言,這可能是個問題。當然,一旦到達方法末尾,這三種數(shù)據(jù)表示方式中的兩種都會落在范圍之外,被垃圾回收器回收。但是,只是觸發(fā)更頻繁的垃圾回收可能會對用戶體驗帶來負面影響,造成處理速度下降。如果內(nèi)存效率和性能很重要,使用 protocol buffers 的解析器可能是個較好的選擇。使用 protocol buffers 處理二進制

Protocol buffers 是一個由 Google 開發(fā)的與語言無關的數(shù)據(jù)串行化格式,旨在比 XML 更快地通過網(wǎng)絡傳送數(shù)據(jù)。它是 Google 用于服務器對服務器調(diào)用的事實 標準。Google 將該格式及其用于 C++、Java 和 Python 編程語言的綁定工具以開源方式提供。

在 清單 3 和 清單 6 中看到 protocol buffers 是二進制格式。如您所料,這使得數(shù)據(jù)很簡潔。如果在客戶端和服務器端啟用 gzip 壓縮,在使用 XML 和 JSON 時通常也可以得到類似的消息大小,但是 protocol buffers 仍然有一些大小上的優(yōu)勢。它還是一種可以迅速解析的格式。最后,它提供了一個相當簡單的 API。 清單 10 顯示了一個示例解析器實現(xiàn):

 

清單 10. Protocol buffers 解析器實現(xiàn)    
 

  1. private class StockProtoBufParser extends BaseStockParser{  
  2.     public StockProtoBufParser(){  
  3.         super("protobuf");  
  4.     }  
  5.     @Override  
  6.     protected Stock[] doInBackground(String... symbols) {  
  7.         Stock[] stocks = new Stock[symbols.length];  
  8.         try{  
  9.             Stocks.Portfolio portfolio =   
  10.                 Stocks.Portfolio.parseFrom(getData(symbols));  
  11.             for (int i=0;i<symbols.length;i++){  
  12.                 stocks[i] = Stock.fromQuote(portfolio.getQuote(i));  
  13.             }  
  14.         } catch (Exception e){  
  15.             Log.e("DayTrader", "Exception getting ProtocolBuffer data", e);  
  16.         }  
  17.         return stocks;  
  18.     }  

如 清單 3 所示,您可以使用 protocol buffers 編譯器生成的 helper 類。這與服務器使用的 helper 類相同。可以編譯它一次,然后在服務器和客戶端共享它。 這樣,您可以更輕松地直接從服務器的流讀取數(shù)據(jù)并將其轉(zhuǎn)換成 Stock 對象數(shù)組。這種簡單編程也具有非常出色的性能。現(xiàn)在看一下此性能與 XML 和 JSON 的比較。

比較性能通常涉及某種微基準測試,此類基準測試很容易產(chǎn)生偏見或無意間得到不正確的結(jié)果。即使以公平方式設計微基準測試,很多隨機因素也會對結(jié)果產(chǎn)生影響。盡管有這些問題,我還是要使用這樣的微基準測試來比較 XML(大約 1300 ms)、JSON(大約 1150 ms)和 protocol buffers(大約 750 ms)。基準測試向服務器發(fā)送了一個關于 200 個股票的請求并測量了從發(fā)出請求到用于創(chuàng)建 ListView 的 Adapter 的數(shù)據(jù)準備就緒所需的時間量。對每個數(shù)據(jù)格式在兩個設備上進行 50 次這樣的操作:一個 Motorola Droid 和一個 HTC Evo,兩個都通過 3G 網(wǎng)絡。 圖 2 顯示了結(jié)果:

圖 2. 比較數(shù)據(jù)格式速度

圖 2 顯示出,在此基準測試中 protocol buffers(大約 750 ms)比 XML (大約 1300 ms)幾乎快兩倍。很多因素影響著數(shù)據(jù)通過網(wǎng)絡和被手持設備處理的性能。一個明顯的因素是通過網(wǎng)絡的數(shù)據(jù)量。二進制格式的 protocol buffers 比文本格式的 XML 和 JSON 在通過網(wǎng)絡時小得多。然而,文本格式可以使用 gzip 進行有效地壓縮,這是 Web 服務器和 Android 設備都支持的標準技術。圖 3 顯示了在打開和關閉 gzip 時通過網(wǎng)絡的數(shù)據(jù)大小:

圖 3. 不同格式的數(shù)據(jù)大小

圖 3 應該增加了您對 XML 和 JSON 之類的文本內(nèi)容的壓縮效果的喜愛(更不用說 Web 格式、HTML、JavaScript 和 CSS 了)。protocol buffers 數(shù)據(jù)(大約 6KB)比原始 XML(大約 17.5KB)或 JSON(大約 13.5KB)數(shù)據(jù)小得多。但是一旦進行了壓縮, JSON 和 XML(都是大約 3KB)實際上比 protocol buffers 小很多了。在本例中,它們都接近于 protocol-buffers 編碼消息大小的一半了。

回到 圖 2,速度的不同顯然不能由通過網(wǎng)絡的消息大小解釋。protocol-buffers 消息比 XML 或 JSON 編碼的消息大,但是通過使用 protocol buffers,您仍然能夠削減半秒鐘的用戶等待時間。這是否意味著應該在 Android 應用程序中使用 protocol buffers 呢?這樣的決定很少是固定的。如果要發(fā)送的數(shù)據(jù)量很小,則三種格式間的差異也不大。對于大量數(shù)據(jù)而言,protocol buffers 可能會有所不同。但是,像這樣精心設計的基準測試無法替代對您自己的應用程序的測試。

結(jié)束語

本文介紹了如何使用 Internet 上流行的兩種數(shù)據(jù)格式 XML 和 JSON 的方方面面。還講到了第三種可能性,protocol buffers。像軟件工程中的其他內(nèi)容一樣,選擇技術主要就是權衡利弊。當您為一個局限的環(huán)境(比如 Android)開發(fā)時,這些決定的結(jié)果往往被放大了。我希望您現(xiàn)在擁有的關于這些后果的額外知識能夠幫助您創(chuàng)建出色的 Android 應用程序。

【編輯推薦】

Android開發(fā)中插入新的Activity

Android應用程序開發(fā)環(huán)境的搭建

給Android添磚加瓦 點心操作系統(tǒng)詳解

Web開發(fā)人員應有的7款免費Android應用

Android應用開發(fā)教程:兩個運行的Activity之間的通信

責任編輯:zhaolei 來源: developerWorks 中國
相關推薦

2009-09-22 12:17:59

ibmdwLotus

2021-09-07 10:24:36

Vue應用程序Web Workers

2009-06-19 13:45:53

Java應用程序Jfreechart

2013-10-09 11:15:49

Ubuntu應用程序

2009-11-23 19:52:55

ibmdwFlex

2022-08-30 20:00:37

零信任Linkerd

2010-07-26 11:02:46

2023-12-07 08:22:58

Android應用

2009-08-27 11:22:30

ibmdw云計算

2023-08-22 20:55:04

AzureLLMTypeChat

2011-10-12 11:24:44

AndroidPC

2011-07-18 10:00:47

iPhone iOS Visual Stu

2009-03-30 10:34:03

ASP.NETMySQL

2011-07-18 10:21:04

iOS Visual Stu iphone

2010-11-30 15:44:27

Windows 7兼容

2022-09-27 15:16:42

開發(fā)Android應用程序

2023-12-22 09:11:45

AndroidNFC移動開發(fā)

2010-03-29 13:35:39

ibmdwRIA

2010-03-03 15:46:40

Android應用程序

2011-05-23 13:43:19

ASP.NETIIS7
點贊
收藏

51CTO技術棧公眾號

亚洲成人7777| 国产日本精品| 欧美精品aⅴ在线视频| 国产三级中文字幕| 成人免费一级视频| 亚洲综合日韩| 日韩网站在线观看| 秋霞午夜鲁丝一区二区| 不卡av播放| 亚洲欧洲精品天堂一级| 国产日韩欧美亚洲一区| 波多野结衣绝顶大高潮| 亚洲九九在线| 亚洲欧美日本另类| 亚洲免费成人在线视频| 密臀av在线播放| 国产精品天美传媒沈樵| 国产乱码精品一区二区三区卡 | 色婷婷狠狠18| 日本高清在线观看视频| 国产欧美一区二区精品性色| 岛国一区二区三区高清视频| 中文字幕欧美在线观看| 亚洲美女黄色| 成人444kkkk在线观看| 波多野结衣片子| 99ri日韩精品视频| 欧美卡1卡2卡| 男人天堂999| 中文字幕伦理免费在线视频| 久久精品在这里| 国产欧美日本在线| 欧美日韩精品一区| 日本在线视频中文字幕| 午夜精品久久久久久久四虎美女版| 亚洲国产另类久久精品| 在线观看视频在线观看| 国产在线|日韩| 午夜精品一区二区三区电影天堂| 亚洲最新在线| 国际av在线| 91在线免费播放| 粉嫩精品一区二区三区在线观看| 91精东传媒理伦片在线观看| 久久婷婷丁香| 51精品国产黑色丝袜高跟鞋| 久久久久久久久久综合| 一区二区三区午夜视频| 中文字幕久精品免费视频| 亚洲黄色免费在线观看| 美女av一区| 欧美mv日韩mv| 波多野结衣网页| 欧美性生活一级| 在线视频一区二区三区| 春日野结衣av| 国产精品vvv| 午夜精品福利一区二区三区av| 成人免费看片'免费看| 在线观看男女av免费网址| 亚洲欧美偷拍卡通变态| 2021国产视频| 日本大片在线播放| 亚洲国产精品欧美一二99| 日韩a级黄色片| 午夜激情在线| 亚洲一区二区三区中文字幕在线| 欧美图片激情小说| 超碰成人av| 日韩欧美精品网址| 中国黄色片免费看| crdy在线观看欧美| 日韩精品一区二区三区视频| 东京热av一区| 日韩成人一级| 在线观看欧美日韩国产| 波多野结衣久久久久| 亚洲精品国产首次亮相| 欧美国产视频日韩| 亚洲 欧美 日韩 综合| 美女诱惑一区| 成人网在线观看| 亚洲成a人片在线| 91免费观看视频| 亚洲精品在线观看免费| 污视频网站在线免费| 亚洲成人免费电影| 成人性做爰aaa片免费看不忠| 国产成人a视频高清在线观看| 91精品一区二区三区久久久久久 | 亚洲欧美第一页| avhd101老司机| 66久久国产| 97精品国产97久久久久久免费| 国产乱国产乱老熟| 久久精品99国产精品日本| 粉嫩av免费一区二区三区| 牛牛热在线视频| 综合中文字幕亚洲| 免费国产a级片| 国产成人免费| 精品久久久久久久一区二区蜜臀| 这里只有久久精品| 欧美一区免费| 国产精品成人在线| 亚洲福利在线观看视频| 国产色91在线| 欧日韩免费视频| 日日狠狠久久| 亚洲欧美另类在线观看| 久久艹精品视频| 奇米综合一区二区三区精品视频| 国产精品自拍首页| 精品麻豆一区二区三区| 色94色欧美sute亚洲线路一久| 亚洲丝袜在线观看| 精品日韩欧美一区| 97视频免费在线观看| 国产女主播福利| 国产欧美日韩精品在线| 日韩欧美不卡在线| 欧美三级电影网址| 日韩成人网免费视频| 九九热视频精品| 精品综合久久久久久8888| 欧美日韩高清在线一区| 多野结衣av一区| 日韩欧美中文字幕精品| 中文字幕无码日韩专区免费| 老**午夜毛片一区二区三区| 国产伦精品一区二区三区在线| 很黄的网站在线观看| 欧美日韩成人激情| 美女被到爽高潮视频| 一本色道久久综合亚洲精品不| 亚洲影视九九影院在线观看| 最新真实国产在线视频| 日韩欧美精品在线观看| 亚洲一区二区三区综合| 亚洲欧洲一级| 99精品在线直播| av网站大全在线| 91精品国产综合久久婷婷香蕉| 一级黄色片网址| 日本91福利区| 亚洲bbw性色大片| 三级成人黄色影院| 亚洲免费一在线| 五月婷婷色丁香| 91蜜桃视频在线| 精品少妇一区二区三区在线| 欧美电影在线观看完整版| 欧美黑人又粗大| 亚洲美女性生活| 亚洲一区免费观看| jjzz黄色片| 亚洲黄色天堂| 美脚丝袜一区二区三区在线观看| 鲁鲁在线中文| 亚洲毛片在线观看.| 黄色一级视频免费看| 久久久777精品电影网影网 | 99精品一区二区三区的区别| 九九久久国产| 欧美成人午夜激情在线| 午夜精品久久久久久久第一页按摩 | 日韩午夜电影在线观看| 真实国产乱子伦对白在线| 国产精品1区2区| www.激情网| 欧洲vs亚洲vs国产| 国产精品jizz在线观看麻豆| 最新av网站在线观看| 56国语精品自产拍在线观看| 欧美爱爱小视频| 成人h版在线观看| 国产麻花豆剧传媒精品mv在线| 精品盗摄女厕tp美女嘘嘘| 国产精品自拍视频| 宅男网站在线免费观看| 日韩精品www| 中文字幕av免费观看| 亚洲免费观看高清完整| 亚洲久久久久久| 日韩国产欧美视频| 中文字幕av日韩精品| 国产在线播放精品| 国产极品精品在线观看| 韩国中文字幕在线| 日韩av在线直播| 国产精品欧美综合| 亚洲欧美激情视频在线观看一区二区三区 | 免费国产一区二区| 成人在线黄色| 欧美精品999| 精品99又大又爽又硬少妇毛片| 欧美精品在线视频| 国产午夜福利精品| 国产精品久久久久久久久快鸭 | 国产欧美日韩三区| 色哟哟网站在线观看| 日韩成人精品在线观看| 国产精品视频一二三四区| 国产麻豆精品久久| 99三级在线| 欧洲成人一区| 777国产偷窥盗摄精品视频| 拍真实国产伦偷精品| 日韩精品中文字幕久久臀| 91精东传媒理伦片在线观看| 精品免费在线视频| 在线观看美女av| 久久亚洲二区三区| 少妇搡bbbb搡bbb搡打电话| 青青草国产精品97视觉盛宴| 欧美老熟妇喷水| 亚洲视频一区| 中文字幕在线中文字幕日亚韩一区| 欧美jizz19性欧美| 成人免费视频视频在| 欧美三级电影网址| 国产成人久久精品| a天堂资源在线| 欧美成年人在线观看| 在线免费看黄| 国产亚洲精品美女久久久久| 日本免费一区视频| 欧美成人精精品一区二区频| 一级做a爱片性色毛片| 欧洲人成人精品| 黄色片中文字幕| 欧美性猛交xxx| 日本少妇在线观看| 亚洲综合久久av| 男的操女的网站| 中文字幕日韩一区二区| 九九热免费在线| 久久精品人人做人人爽人人| 欧美熟妇精品一区二区蜜桃视频| 国产麻豆成人精品| 亚洲va在线va天堂va偷拍| 天堂在线一区二区| 欧美 激情 在线| 欧美一级视频| 成人黄色片视频| 麻豆91精品| 国产一区二区视频免费在线观看 | 97超级碰碰碰| 美女91在线看| 日本高清视频一区| 国模套图日韩精品一区二区| 国产成人jvid在线播放| 日韩国产网站| 国产精品一区二区久久久久| 国产91亚洲精品久久久| 成人福利在线视频| 91成人精品观看| 亚洲永久在线观看| 亚洲电影一区| 精品国产免费久久久久久尖叫| 欧美成人基地| 日韩欧美激情一区二区| 久久在线电影| 成年丰满熟妇午夜免费视频| 国内自拍视频一区二区三区| 国产精品69久久久| 99在线|亚洲一区二区| 午夜精品久久久久久久无码| 国产亚洲精品bv在线观看| 日韩欧美亚洲天堂| 久久精品女人| 亚洲天堂2018av| 国产资源在线一区| 少妇被狂c下部羞羞漫画| 久久亚洲二区三区| 精品少妇一区二区三区密爱| 一区二区在线免费| 国产一区二区99| 欧美午夜免费电影| 亚洲成人久久精品| 亚洲毛茸茸少妇高潮呻吟| 午夜小视频在线| 久久久久久久久91| 日韩在线短视频| 97夜夜澡人人双人人人喊| 一区二区三区韩国免费中文网站| 亚洲成人自拍视频| 激情丁香综合| 久久久国产欧美| 国产成人av网站| 一区二区三区伦理片| 亚洲精品视频一区| 日韩欧美一级视频| 欧美色图一区二区三区| www.成人精品| 夜夜嗨av一区二区三区免费区 | 日韩a一区二区| 日韩免费在线观看av| 日韩不卡一区二区| 又黄又爽又色的视频| 国产亚洲欧美日韩日本| 日本成人在线免费视频| 激情综合婷婷| 韩日午夜在线资源一区二区 | 亚洲天堂精品在线| 在线电影福利片| 国产高清在线不卡| 加勒比中文字幕精品| 久久最新免费视频| 狂野欧美性猛交xxxx巴西| 国产精品熟妇一区二区三区四区| 国产精品视频第一区| 亚洲精品1区2区3区| 欧美一区午夜精品| 国产露出视频在线观看| 亚洲97在线观看| 日本一区影院| 亚洲7777| 日韩精品福利网| 天堂久久久久久| 亚洲一二三级电影| 国产又粗又猛又爽又黄视频| 亚洲性av在线| 性国裸体高清亚洲| 成人在线视频网址| 性欧美69xoxoxoxo| 国产高清视频网站| 国产午夜一区二区三区| 亚洲伊人成人网| 精品国产sm最大网站免费看| 91亚洲天堂| 91久久久在线| 天堂美国久久| 五月天婷婷亚洲| 国产精品欧美极品| 日本久久综合网| 亚洲欧美日韩高清| 免费一二一二在线视频| 国产日韩三区| 亚洲电影av| 中国特级黄色大片| 亚洲图片欧美一区| 亚洲男人第一天堂| 欧美激情视频在线观看| 免费看日产一区二区三区| 亚洲精品国产精品久久| 另类调教123区 | 久久神马影院| 亚欧激情乱码久久久久久久久| 中文字幕va一区二区三区| 中国女人真人一级毛片| 日韩专区在线观看| 国产免费区一区二区三视频免费| 最新中文字幕久久| 国内精品视频一区二区三区八戒| 欧美日韩黄色网| 日韩女优视频免费观看| 日本乱理伦在线| 久久99蜜桃综合影院免费观看| 亚洲欧美久久久| 欧洲性xxxx| 欧美一卡二卡在线观看| 狂野欧美性猛交xxxxx视频| 国产日韩欧美综合精品 | 婷婷免费在线观看| 亚洲图片激情小说| 亚洲国产精品一| 97成人超碰免| 狠狠色狠狠色综合婷婷tag| 少妇一级淫免费放| 亚洲欧美日韩电影| 深夜福利视频网站| 国产成人在线视频| 91亚洲国产高清| 波多野吉衣在线视频| 欧美日韩精品中文字幕| 国产中文字幕在线观看| 成人黄色生活片| 9色国产精品| 免费成人深夜蜜桃视频| 日韩精品一区二区三区四区 | 成人精品久久一区二区三区| 欧美一区久久| 黄色短视频在线观看| 欧美三级乱人伦电影| 午夜小视频福利在线观看| 久久天堂国产精品| 久久91精品久久久久久秒播| 免费在线一级片| 亚洲午夜女主播在线直播| 日韩精品一区国产| 美女福利视频在线| 亚洲日韩欧美一区二区在线| 亚洲色图狠狠干| 国产日韩欧美成人| 国产精品一级| 天天综合天天做| 亚洲人成网7777777国产| 日韩08精品| 三上悠亚在线一区二区|