Android網絡編程詳解

1、網絡的基本概念及Http協議

IP地址和端口號java

  • IP地址:網絡中的媚態計算機都必須一個惟一的IP地址做爲標識,用一組由「.」分隔的十進制數組成
  • 端口號:IP地址只能保證鍵數據送到指定的計算機,但沒法知道交給該主機的哪一個網絡程序,所以採用端口號標識計算機上正在運行的進程
  • 每一個被髮送的網略數據包都包含端口號,用於將該數據幀交給具備相同端口號的應用程序處理

Java的網絡編程由Java.net包中的類進行處理android

  • InetAddress類:描述IP地址

HTTP協議

  • 屬於應用層的面向對象的協議,適用於分佈式超媒體信息系統git

  • 主要特色github

    一、支持C/S模式編程

    二、簡單快速:只需傳送請求方法和路徑,請求方法經常使用的有:GET、HEAD、POST等數組

    三、靈活:容許傳輸任意類型的數據對象,用Content-Type進行標記緩存

    四、無鏈接:限制每次鏈接只處理一個請求安全

    五、無狀態:對事務處理沒有記憶功能服務器

  • HTTP的URL的格式:網絡

    一、http://host[:port][/path]

    二、http表示要經過HTTP協議來定位網絡資源;host表示合法的Internet主機域名或者IP地址;port指定一個端口號,爲空則使用默認端口80;path指定請求資源的URI

HTTP請求報文

  • 由請求行、請求報頭、空行和請求數據4個部分組成

HTTP相應報文

  • 由狀態行、消息報頭、空行、相應正文組成

常見的狀態碼

  • 200 OK:客戶端請求成功
  • 400 Bad Request:客戶端請求有語法錯誤,不能被服務器所理解
  • 400 Unauthorized:請求未經受權,這個狀態碼必須和WWW-Authenticate報頭域一塊兒使用
  • 403 Forbidden:服務器收到請求,可是拒絕提供服務
  • 404 Not Found:服務器沒法根據客戶端的請求找到資源
  • 500 Internal Server Error:服務器發生不可預期的錯誤
  • 503 Server Unavailable:服務器當前不能處理客戶端的請求,一段時間後可能恢復正常

https請求

  • HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,也就是HTTP的安全版
  • HTTPS=HTTP+SSL/TLS
  • HTTPS的安全基礎是SSL

2、Android的網絡編程

Android的網絡編程

一、HTTP通訊方式

HttpURLConnection

  • Android 2.3以後,HttpURLConnection是Android網絡編程的最佳選擇,它的API簡單,體積較小,壓縮和緩存機制有效較少網絡訪問的流量

HttpClient

  • 開發團隊向開發者建議:在Android 2.2版本及如下可使用HttpClient,在2.3以上版本則應該使用HttpURLConnection
  • Android 6.0直接刪除了HttpClient類庫

二、Socket通訊方式

Android P的http網絡請求的問題

Android p要求默認使用加密鏈接,禁止APP使用任何未加密的鏈接,所以須要使用TLS傳輸層安全協議,也就是Https

Android P使用HttpUrlConnection進行http的get請求會出現如下異常

  • W/System.err:java.io.IOException:Cleartext HTTP traffic to **** not permitted

解決方案

  • 推薦:使用Https鏈接
  • targetSdkVersion降到27級如下版本
  • 更改網絡安全配置,此更改與網站有關,有時不能獲得相應

更改網絡安全配置

在res新增xml目錄,建立network_security_config.xml,開啓http請求

<network-security-config>
 <base-config cleartextTrafficPermitted="true"/>
 </network-security-config>

在AndroidMainfest.xml中的application標籤增長如下屬性

  • android:networkSecurityConfig="@xml/network"

Android的Https

自定義X509TrustManager

  • 在使用HttpsURLConnection發起HTTPS請求的時候,提供了一個自定義的X509TrustManager,未實現安全校驗邏輯
  • 若是不提供自定義X509TrustManager,代碼運行起來可能會報異常

自定義HostnameVerifier

  • 在握手期間,若是URL的主機名和服務器的標識主機名不匹配,則驗證機制能夠回調此接口的實現程序來肯定是否應該容許此連接

URL類

一、統一資源定位符(URL)是對能夠從互聯網上獲得的資源的位置和訪問方法的一種簡潔的表示,是互聯網上標準資源的地址

二、互聯網上的每一個文件都有一個惟一的URL

三、URL類提供了多個構造器用於建立URL對象

四、URL類提供多個方法訪問URL對應的資源:

  • URLConnection openConnection():返回一個URLConnection對象,它表示到URL所引用的遠程對象的鏈接
  • InputStream openStream():打開此URL的鏈接,並返回一個用於讀取該URL資源的InputStream

Android URL通訊

一、Android HTTP URL接口的基本操做包括:

  • 建立URL以及HttpURLConnection對象
  • 鏈接參數設置
  • 鏈接到服務器
  • 向服務器寫數據
  • 從服務器讀取數據

二、HttpURLConnection的屬性設置

connection.setConnectTimeout(15000);
        connection.setReadTimeout(15000);
        connection.setRequestMethod(method);
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) " +
                "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
        connection.setDoInput(true);
        if("POST".equals(method)){
            connection.setDoOutput(true);
        }

三、HttpURLConnection訪問HTTP資源的步驟:

(1)根據URL地址建立URL對象

(2)使用URL對象的openConnection()方法獲取HttpURLConnection對象

(3)設置鏈接的屬性,包括GET/POST請求方式

(4)輸入、輸出數據

(5)關閉輸入、輸出流

(6)在AndroidManifest配置文件中設置訪問INTERNET的權限

四、GET方式

// 一、將url字符串轉爲URL對象
        URL url = new URL(urlPath);
 //            二、得到HttpURLConnection對象
        connection = (HttpURLConnection) url.openConnection();
//            三、設置鏈接的相關參數
        connection.setRequestMethod("GET");
        connection.setUseCaches(false);
        connection.setConnectTimeout(15000);
        connection.setReadTimeout(15000);
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) " +
                "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
        connection.setDoInput(true);

  //            四、配置https的證書
        if ("https".equalsIgnoreCase(url.getProtocol())) {
            ((HttpsURLConnection) connection).setSSLSocketFactory(
                    HttpsUtil.getSSLSocketFactory());
        }
   //            五、進行數據的讀取,首先判斷響應碼是否爲200
        if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
    //                得到輸入流
            is = connection.getInputStream();
    //                包裝字節流爲字符流
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
   //                讀取數據
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
   //                六、關閉資源
            is.close();
            connection.disconnect();
  //                七、返回結果
            return response.toString();

五、POST方式

String body=getParamString(params);
        byte[] data=body.getBytes();

        URL url=new URL(urlPath);

        connection= (HttpsURLConnection) url.openConnection();
        //            三、設置鏈接的相關參數
        connection.setRequestMethod("POST");
        connection.setUseCaches(false);
        connection.setConnectTimeout(15000);
        connection.setReadTimeout(15000);
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) " +
                "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
        connection.setDoInput(true);
        connection.setDoOutput(true);

  //            四、配置https的證書
        if ("https".equalsIgnoreCase(url.getProtocol())) {
            ((HttpsURLConnection) connection).setSSLSocketFactory(
                    HttpsUtil.getSSLSocketFactory());
        }
        connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
        connection.setRequestProperty("Content-Length",String.valueOf(data.length));
        OutputStream os=connection.getOutputStream();
        os.write(data);
        os.flush();

        if(connection.getResponseCode()==HttpURLConnection.HTTP_OK){

           is=connection.getInputStream();
           BufferedReader reader=new BufferedReader(new InputStreamReader(is));
            //                讀取數據
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
 //                六、關閉資源
            is.close();
            connection.disconnect();
 //                七、返回結果
            return response.toString();
        }

六、HttpURLConnection使用的注意事項

  • 使用setConnectTimeout()方法設置鏈接超時,當網絡很差使,Android系統會在超時設置時間後收回資源,中斷操做
  • 經過getResponseCode()對響應碼進行判斷,若是返回的相應碼爲200,則表示鏈接成功
  • 在對大文件操做時,要將文件寫道SDCard上,不要直接寫到手機內存上
  • 操做大文件時,要一邊從網絡上讀取,一邊往SDCard上寫入,減小手機內存的使用
  • 對文件流操做完畢後要及時關閉
  • Android4.0後全部網絡通訊的操做都不能在主線程進行,須要使用獨立的線程完成

OKHttp

  • 官網:square.github.io/okhttp/

  • 源碼:github.com/square/okht…

  • 配置:

    1. OKHttp是Android 2.3及其以上版本,Java要求JDK1.7以上

    2. 添加依賴:

      implementation 'com.squareup.okhttp3:okhttp:4.2.1'
    3. 添加權限:

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

    1. 0KHttp是Android版Http喀戶端,很是高效,支持SPDY、鏈接池、GZIP和HTTP緩存。
    2. 默認狀況下,0KHttp會自動處理常見的網絡問題,像二次鏈接、SSL的握手問題。
    3. 若是應用程序集成了0KHttp,Retrofit默認會使用0KHttp處理其餘網絡層請求。
    4. 從Android4.4開始,HttpURLConnection的底層實現採用了okHttp。
  • OkHttp開發基本思路

    1. 0kHttp的每次網絡請求是一個Request,提供Request必要的參數url、header等,基於Request構造出一個Call對象,再調用它的execute( )方法,就能取得WebServer回覆的數據。
    2. 若是同步調用,須要在獨立的線程中執行,使傭異步調用,則採用回調的方式執行,在內部封裝了一個請求隊列。
    3. OkHttp依賴另外一個組件okiO完成高性能的I/O操做
    4. 基本用法:新建一個OkHttpClient對象;經過Request.Builder對象新建一個Request對象;經過Request對象構造Call對象,調用enqueue()以異步的方式將call加入調度隊列,等待request執行完成;經過Call對象的Callback對象返回執行結果。
    5. 一直等待http請求,直到返回響應,請求期間會阻塞進程,所以不能在Android的主線程執行,須要用Android的多線程方式進行處理,不然會報錯。
  • Get同步請求

    1. 當HTTP響應碼位於200到300之間時,認爲操做是成功的
    2. response.body()返回-個ResponseBody對象,封裝了HTTP響應的主體數據,它的string()方法將這些數據轉換爲字符串,另外一個byteStream()方法則返回一個InputStream流
    3. 注意事項:要獨立的線程中執行網絡操做;對於超過1MB的響應body,應使用流的方式來處理body。
    4. 通常不適用
  • Get異步請求

    1. 在另外的工做線程中執行http請求,請求時不會阻塞當前的線程,因此能夠在Android主線程中使用。
    2. 異步請求須要加入到一個請求隊列中,而且要指定回調方法。
  • post異步請求

    1.經過RequestBody構建請求數據

    private void postForm(String url){
    RequestBody formBody = new FormBody.Builder().add("city","南京").build();
     Request request = new Request. Builder().url(url).post(formBody).build();
    mClient.newCall(request).enqueue(new Callback(){
    @Override
    public void onResponse(Call call, Response response) throws IOException {
    final String str = response .body().string();
    Log.d(TAG, str);
    runOnUiThread(new Runnable() {
      @Override
     public void run() {
     textView. setText(str);
    });
    }
    @Override
    public void onFailure(Call call,   IOException e) {
     });
    }
  • 圖片加載框架Glide

    1. 添加依賴:

      implementation 'com.github.bumptech.glide:glide:4.10.0'
      annotationProcessor 'com. github.bumptech.glide:compiler:4.10.0'
       //https圖片處理
      implementation "com.github.bumptech.glide:okhttp3-integration:4.10.0"
    2. 添加網絡權限:

      <uses-permission android: name= "android. permi ssion . INTERNET" />
    3. 使用:

      Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
    4. 加載圖片的通常方法:

      Glide.with(Context context).load(String url).into(ImageView imageView);
  • Glide加載https圖片

    1. 建立支持https的OkHttpClient對象:

      public static 0kHttpClient handleSSLHandshakeBy0kHttp() {
      return new 0kHttpClient.Builder()
      .connectTimeout(10,TimeUnit. SECONDS)
      .writeTimeout(10,TimeUnit. SECONDS)
      .readTimeout(10,TimeUnit . SECONDS)
       //支持HTTPS請求,跳過證書驗i證
      .sslSocketFactory(getSSLSocketFactory(),(X509TrustManager) getTrustManager()[0])
      .hostnameVerifier(new TrustAllHostnameVerifier())
      .build();
      }
    2. 建立繼承AppGlidModule類的自定義類,重寫registerComponents( )方法:

      @GlideModule
      public class OkHttpGlideModule extends AppGlideModule {
       @Override
       public void registerComponents( @NonNull Context context,
       @NonNull Glide glide,@NonNull Registry registry) {
      OkHttpClient client = HttpsUtil.handl esSLHandshakeByokHttp();
       registry.replace(GlideUrl.class,InputStream.class,
       new 0kHttpUrlLoader.Factory(client));
       }
      }

今年年初我花一個月的時間收錄整理了一套知識體系,若是有想法深刻的系統化的去學習的,能夠點擊傳送門,我會把我收錄整理的資料都送給你們,幫助你們更快的進階。

相關文章
相關標籤/搜索