天天看點

[Android][第一行代碼][第 9 章 網絡技術]

01. WebView

  1. 使用 WebView 加載網頁
    private void initWebView() {
     wb_net.getSettings().setJavaScriptEnabled(true);// 支援 JavaScript 腳本
     wb_net.setWebViewClient(new WebViewClient());// 網頁跳轉仍在目前浏覽器
     wb_net.loadUrl("http://www.baidu.com");// 加載網頁
    }
               
  2. 方法
    • setWebViewClient()

      方法作用,當需要從一個網頁跳轉另一個網頁時,目标網頁仍然在目前 WebView 中顯示,而不是打開系統浏覽器。
  3. 網絡權限
    <uses-permission android:name="android.permission.INTERNET" />
               

02. 使用 HTTP 協定通路網絡

  1. 工作原理

    用戶端向伺服器發出一條 HTTP 請求,伺服器收到請求之後傳回一些資料給用戶端,然後用戶端再對這些資料進行解析和處理就可以了。

  2. 使用 HttpURLConnection
    private void sendRequestWithHttpURLConnection() {
     new Thread(new Runnable() {// 網絡請求耗時操作放在子線程中
    
       @Override
       public void run() {
         HttpURLConnection httpURLConnection = null;// 連接配接對象
         BufferedReader bufferedReader = null;// 資料讀取流
         try {
           URL url = new URL("http://www.baidu.com");// URL 對象
           httpURLConnection = (HttpURLConnection) url.openConnection();// 打開連接配接
           httpURLConnection.setRequestMethod("GET");// 設定網絡請求模式
           httpURLConnection.setConnectTimeout();// 設定連接配接逾時時間
           httpURLConnection.setReadTimeout();// 設定資料讀取逾時時間
           InputStream inputStream = httpURLConnection.getInputStream();// 擷取資料讀取流
           bufferedReader = new BufferedReader(new InputStreamReader(inputStream));// 對流封裝提供效率
           StringBuilder response = new StringBuilder();// 請求結果
           String line;
           while ((line = bufferedReader.readLine()) != null) {
             response.append(line);// 從資料讀取流中讀取資料
           }
           showResponse(response.toString());// 進行界面展示
         } catch (IOException e) {
           e.printStackTrace();
         } finally {
           if (bufferedReader != null) {
             try {
               bufferedReader.close();// 關閉資料流
             } catch (IOException e) {
               e.printStackTrace();
             }
           }
           if (httpURLConnection != null) {
             httpURLConnection.disconnect();// 關閉網絡連接配接
           }
         }
       }
     }).start();
    }
    
    private void showResponse(final String response) {
     runOnUiThread(new Runnable() {// 界面重新整理的工作必須放在主線程中
    
       @Override
       public void run() {
         tv_result.setText(response);
       }
     });
    }
               
  3. 小細節
    • 網絡請求模式有

      GET

      POST

      等,其中

      GET

      表示希望從伺服器那裡擷取資料,而

      POST

      表示希望送出資料給伺服器。
    • 設定網絡連接配接逾時時間
    • 設定資料讀取逾時時間
    • 設定請求頭資料
    • 網絡請求等耗時操作需要放在子線程
    • 界面控件重新整理需要放在主線程

03. 使用 OKHttp

  1. 添加依賴
  2. 使用 OKHttp
    private void sendRequestWithOkHttp() {
     new Thread(new Runnable() {// 網絡請求耗時操作放在子線程中
    
       @Override
       public void run() {
         try {
           OkHttpClient okHttpClient = new OkHttpClient();// OK 用戶端
           RequestBody requestBody = new FormBody.Builder()
               .add("userName", "admin")
               .add("passWord", "232323")
               .build();// 參數封裝
           Request request = new Request.Builder()
               .url("https://www.baidu.com")
               .post(requestBody)// 用 POST 請求攜帶參數
               .build();
           Response response = okHttpClient.newCall(request).execute();// 執行請求傳回響應對象
           String responseContent = response.body().string();// 從響應對象中擷取字元串
           showResponse(responseContent);// 進行界面展示
         } catch (IOException e) {
           e.printStackTrace();
         }
       }
     }).start();
    }
               

04. Pull 方式解析 XML

  1. XML 格式資料内容
    <apps>
     <app>
       <id>1</id>
       <name>Google</name>
       <version>1.1</version>
     </app>
     <app>
       <id>2</id>
       <name>FaceBook</name>
       <version>1.2</version>
     </app>
     <app>
       <id>3</id>
       <name>Twitter</name>
       <version>1.3</version>
     </app>
    </apps>
               
  2. 使用 Pull 解析
    private void parseXMLWithPull(String responseContent) {
     try {
       XmlPullParserFactory xmlPullParserFactory = XmlPullParserFactory.newInstance();// 擷取工廠執行個體
       XmlPullParser xmlPullParser = xmlPullParserFactory.newPullParser();// 工廠執行個體擷取一個解析器
       xmlPullParser.setInput(new StringReader(responseContent));// 以流的方式給解析器設定資料源
       int eventType = xmlPullParser.getEventType();// 擷取事件類型
       String id = "";
       String name = "";
       String version = "";
       while (eventType != XmlPullParser.END_DOCUMENT) {// 不是文檔結尾
         String nodeName = xmlPullParser.getName();// 擷取節點名稱
         switch (eventType) {// 事件類型
           case XmlPullParser.START_TAG:// 标簽開始
             if ("id".equals(nodeName)) {// 判斷标簽名稱
               id = xmlPullParser.nextText();// 擷取标簽中的内容
             } else if ("name".equals(nodeName)) {
               name = xmlPullParser.nextText();
             } else if ("version".equals(nodeName)) {
               version = xmlPullParser.nextText();
             }
             break;
           case XmlPullParser.END_TAG:// 标簽結束
             if ("app".equals(nodeName)) {
               LogUtils.e("id = " + id + " name = " + name + " version = " + version + "\n");
             }
             break;
           default:
             break;
         }
         eventType = xmlPullParser.next();// 擷取下一個事件
       }
     } catch (Exception e) {
       e.printStackTrace();
     }
    }
               
  3. 重要方法
    • getName()

      方法擷取目前節點名稱
    • nextText()

      方法擷取目前節點内的具體内容

05. SAX 方式解析 XML

  1. 自定義 SaxHandler 繼承自 DefaultHandler
    /**
    * 9.3.2 SAX 解析方式
    *
    * @author JustDo23
    * @since 2017年08月01日
    */
    public class SaxHandler extends DefaultHandler {
    
     private String nodeName;
     private StringBuilder id;
     private StringBuilder name;
     private StringBuilder version;
    
     /**
      * 開始解析文檔
      *
      * @throws SAXException 異常
      */
     @Override
     public void startDocument() throws SAXException {
       super.startDocument();
       id = new StringBuilder();
       name = new StringBuilder();
       version = new StringBuilder();
     }
    
     /**
      * 開始解析節點
      *
      * @param uri        命名空間字元串[可能為空]
      * @param localName  節點名稱[可能為空]
      * @param qName      限定名[可能為空]
      * @param attributes 屬性
      * @throws SAXException 異常
      */
     @Override
     public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
       super.startElement(uri, localName, qName, attributes);
       nodeName = localName;// 目前節點名稱
     }
    
     /**
      * 擷取節點内容[可能會調用多次,一些換行符也被當作内容解析出來]
      *
      * @param ch     位元組數組
      * @param start  起始位置
      * @param length 有效長度
      * @throws SAXException
      */
     @Override
     public void characters(char[] ch, int start, int length) throws SAXException {
       super.characters(ch, start, length);
       if ("id".equals(nodeName)) {
         id.append(ch, start, length);
       } else if ("name".equals(nodeName)) {
         name.append(ch, start, length);
       } else if ("version".equals(nodeName)) {
         version.append(ch, start, length);
       }
     }
    
     /**
      * 完成節點解析
      *
      * @param uri       命名空間字元串[可能為空]
      * @param localName 節點名稱[可能為空]
      * @param qName     限定名[可能為空]
      * @throws SAXException 異常
      */
     @Override
     public void endElement(String uri, String localName, String qName) throws SAXException {
       super.endElement(uri, localName, qName);
       if ("app".equals(localName)) {
         LogUtils.e("id = " + id.toString() + " name = " + name.toString() + " version = " + version.toString() + "\n");
         id.setLength();
         name.setLength();
         version.setLength();
       }
     }
    
     /**
      * 完成文檔解析
      *
      * @throws SAXException 異常
      */
     @Override
     public void endDocument() throws SAXException {
       super.endDocument();
       LogUtils.e("SAX 解析結束");
     }
    
    }
               
  2. 使用 SAX 解析
    private void parseXMLWithSAX(String responseContent) {
     try {
       SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();// 擷取工廠執行個體
       XMLReader xmlReader = saxParserFactory.newSAXParser().getXMLReader();// 利用工廠擷取解析器後擷取XML讀取器
       SaxHandler saxHandler = new SaxHandler();// 執行個體化自定義的 Handler
       xmlReader.setContentHandler(saxHandler);//  讀取器設定 Handler
       xmlReader.parse(new InputSource(new StringReader(responseContent)));// 開始解析
     } catch (Exception e) {
       e.printStackTrace();
     }
    }
               

06. 解析 JSON 格式資料

  1. json 格式資料内容
    [
     {
       "id": "4",
       "name": "Chrome",
       "version": "1.4"
     },
     {
       "id": "5",
       "name": "Safari",
       "version": "1.5"
     },
     {
       "id": "6",
       "name": "Firefox",
       "version": "1.6"
     }
    ]
               
  2. 使用 JSONObject
    private void parseJson(String responseContent) {
     try {
       JSONArray jsonArray = new JSONArray(responseContent);// 擷取數組對象
       for (int i = ; i < jsonArray.length(); i++) {// 對數組進行循環
         JSONObject jsonObject = jsonArray.getJSONObject(i);// 挨個擷取JSONObject
         String id = jsonObject.getString("id");
         String name = jsonObject.getString("name");
         String version = jsonObject.getString("version");
         LogUtils.e("id = " + id + " name = " + name + " version = " + version + "\n");
       }
     } catch (Exception e) {
       e.printStackTrace();
     }
    }
               
  3. 使用 Gson
    1. 添加依賴
    2. 定義實體類
    3. 使用 Gson
      private void parseJsonWithGson(String responseContent) {
      Gson gson = new Gson();// 執行個體化對象
      List<Product> productList = gson.fromJson(responseContent, new TypeToken<List<Product>>() {}.getType());// 解析數組方法
      for (Product product : productList) {
        LogUtils.e("id = " + product.getId() + " name = " + product.getName() + " version = " + product.getVersion() + "\n");
      }
      }
                 

07. 最佳實踐

  1. 回調接口
    public interface HttpCallBackListener {
    
     /**
      * 網絡請求完成時回調
      *
      * @param response 傳回資料
      */
     void onFinish(String response);
    
     /**
      * 網絡請求出現錯誤
      *
      * @param e 異常
      */
     void onError(Exception e);
    
    }
               
  2. 工具類封裝
    public class HttpUtil {
    
     public static void sendHttpRequest(final String address, final HttpCallBackListener httpCallBackListener) {
       new Thread(new Runnable() {
    
         @Override
         public void run() {
           HttpURLConnection httpURLConnection = null;
           try {
             URL url = new URL(address);
             httpURLConnection = (HttpURLConnection) url.openConnection();
             httpURLConnection.setRequestMethod("GET");
             httpURLConnection.setConnectTimeout();
             httpURLConnection.setReadTimeout();
             httpURLConnection.setDoInput(true);
             httpURLConnection.setDoOutput(true);
             InputStream inputStream = httpURLConnection.getInputStream();
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
             StringBuilder response = new StringBuilder();
             String line;
             while ((line = bufferedReader.readLine()) != null) {
               response.append(line);
             }
             if (httpCallBackListener != null) {
               httpCallBackListener.onFinish(response.toString());
             }
           } catch (Exception e) {
             if (httpCallBackListener != null) {
               httpCallBackListener.onError(e);
             }
           } finally {
             if (httpURLConnection != null) {
               httpURLConnection.disconnect();
             }
           }
         }
       }).start();
     }
    
     public static void sendOkHttpRequest(String address, okhttp3.Callback callback) {
       OkHttpClient okHttpClient = new OkHttpClient();
       Request request = new Request.Builder()
           .url(address)
           .build();
       okHttpClient.newCall(request).enqueue(callback);// 開啟子線程
     }
    
    }
               
  3. 注意線程問題

08. 小結

  1. 對 WebView 進行更詳細的學習使用。
  2. 對 HTTP 協定進行更詳細的學習使用。
  3. 如果可以那就看看 OKHttp 等的源碼解析。
  4. 其他第三方網絡請求架構簡單了解。

繼續閱讀