1. 程式人生 > >Android 學習筆記——使用 HTTP 協議訪問網路

Android 學習筆記——使用 HTTP 協議訪問網路

在 Android 上傳送 HTTP 請求一般有兩種方式:HttpURLConnection 和 HttpClient,由於 HttpClient 存在 API 數量過多、擴充套件困難等問題,在 Android 6.0 已經被完全淘汰,因此官方建議使用 HttpConnetion。
除了 HttpConnection,還有許多出色的網路通訊庫可供我們使用,比如 Square 開發的 OktHttp,在介面封裝上做的簡單易用,便於滿足我們開發時的網路通訊需求。
OkHttp的專案地址:https://github.com/square/okhttp

下面開始介紹這兩種 Android 訪問網路工具的一些基本使用方法。

訪問網路之前需要再在AndroidManifest.xml 檔案中宣告網路許可權

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

1、使用 HttpURLConnection

1.1、向伺服器請求資料

1、獲取 HttpURLConnection 的例項,一般只需要 new 出一個 URL 物件,並傳入目標的網路地址,再呼叫 URL 物件的 openConnection( ) 方法即可。

URL url = new URL("www.baidu.com");
HttpURLConnection connection =
url.openConnection();

2、得到 HttpURLConnection 例項之後,可以設定 HTTP 請求所使用的方法,如 GET(從服務端獲取資料) 和 POST(傳送資料給服務端),寫法如下:

connection.setRequestMethod("GET");

除此之外還可以進行一些自由的定製,如設定連線超時、讀取超時等,根據自己的需求編寫,如:

connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);

3、呼叫 getInputStream() 方法獲取伺服器返回的輸入流,再對輸入流進行處理。

InputStream inputStream = connection.getInputStream();

4、呼叫disconnect()方法還將 HTTP 連線關閉。

connection.disconnect();

demo:

public class MainActivity extends AppCompatActivity {

    private Button sendRequest;
    private TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sendRequest = (Button) findViewById(R.id.btn_send_request);
        responseText = (TextView) findViewById(R.id.tv_respnse_text);
        sendRequest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

    private void sendRequestWithHttpURLConnection() {
        //網路訪問需要在子執行緒內操作
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                BufferedReader reader = null;
                try {
                    URL url = new URL("www.baidu.com");
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(5000);
                    connection.setReadTimeout(5000);
                    InputStream inputStream = connection.getInputStream();
                    reader = new BufferedReader(new InputStreamReader(inputStream));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    showResponse(response.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (reader != null) {
                        try {
                            reader.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }

    private void showResponse(final String response) {
        //Android不允許在子執行緒內進行UI操作,因此需要用這個方法切換到主執行緒進行UI操作
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                responseText.setText(response);
            }
        });
    }
}

1.2、向伺服器提交資料

如果需要向伺服器提交資料,只需將 HTTP 的請求方法改成 POST 即可,注意每條資料都要以鍵值對的形式存在,資料與資料之間用 "&" 隔開,如:

connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=matt&&password=admin");

2、使用 OkHttp

準備工作:
使用 OkHttp 之前需要在專案中新增 OkHttp 庫的依賴,修改 app/build.gradle 檔案,在 dependencies 閉包中新增如下內容:

implementation 'com.squareup.okhttp3:okhttp:3.4.1'

新增完之後不要忘了點選 Sync Now 同步一下

OkHttp 的具體用法:

2.1、向伺服器請求資料

1、建立一個 OkHttpClient 例項

OkHttpClient client = new OkHttpClient();

2、發起 HTTP 請求,需建立一個 Request 物件

 Request request = new Request.Builder().build();

這個物件是一個空的物件,還需要在 build() 方法前連綴其他的方法,如設定目標的網路地址:

Request request = new Request.Builder()
                            .url("http://www.baidu.com")
                            .build();

3、呼叫 OkHttpClient 的 newCall() 方法 建立一個 Call 物件,並呼叫它的 execute() 方法來發送請求並獲取伺服器返回的資料:

 Response response = client.newCall(request).execute();

response 物件就是伺服器返回的資料,可以通過如下方法來獲取返回的具體內容:

 String responseData = response.body().string();

demo:

package com.mattyang.httptest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.IOException;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {

    private Button sendRequest;
    private TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sendRequest = (Button) findViewById(R.id.btn_send_request);
        responseText = (TextView) findViewById(R.id.tv_respnse_text);
        sendRequest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendRequestWithHttpURLConnection();
            }
        });
    }

    private void sendRequestWithHttpURLConnection() {
        //網路訪問需要在子執行緒內操作
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    OkHttpClient client = new OkHttpClient();
                    Request request = new Request.Builder().
                            url("http://www.baidu.com")
                            .build();
                    Response response = client.newCall(request).execute();
                    String responseData = response.body().string();
                    showResponse(responseData);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void showResponse(final String response){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                responseText.setText(response);
            }
        });
    }

}

相較於 HttpURLConnection ,OkHttp 的程式碼量更少,犯錯率也大大降低,因此更為推薦使用 OkHttp 來作為網路通訊庫。

2.2、向伺服器傳送資料

1、構建一個 RequestBody 物件來存放待提交的引數:

RequestBody requestBody = new FormBody.Builder()
                        .add("username","matt")
                        .add("password","admin")
                        .build();

2、在 Request.Builder 中呼叫 post() 方法,並將 RequestBody 物件傳入:

Request request = new Request.Builder()
                        .url("http://www.baidu.com")
                        .post(requestBody)
                        .build();

3、接下來的操作同 GET ,呼叫 execute() 方法來發送請求並獲取伺服器返回的資料。

OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
String responseData = response.body().string();

在 Android 9.0 中,為保證使用者資料和裝置的安全,Google針對下一代 Android 系統(Android P)
的應用程式,將要求預設使用加密連線,這意味著 Android P 將禁止 App 使用所有未加密的連線,因此執行 Android P
系統的安卓裝置無論是接收或者傳送流量,未來都不能明碼傳輸,需要使用下一代(Transport Layer
Security)傳輸層安全協議,而 Android Nougat 和 Oreo 則不受影響。 因此,在Android
P系統的裝置上,如果應用使用的是非加密的明文流量的 HTTP 網路請求,則會導致該應用無法進行網路請求,HTTPS
則不會受影響,同樣地,如果應用嵌套了 WebView,WebView 也只能使用 HTTPS 請求。

面對這種問題,有一下三種解決方法:

(1)APP改用https請求

(2)targetSdkVersion 降到27以下

(3)更改網路安全配置

詳情請戳Android高版本聯網失敗報錯:Cleartext HTTP traffic to xxx not permitted解決方法

相關資料:
《第一行程式碼》第二版——郭霖 人民郵電出版社
https://blog.csdn.net/gengkui9897/article/details/82863966