文章目錄
- WebView
- HTTP
- 使用HttpURLConnection
- 使用OkHttp
- 封裝網絡操作
- 封裝HttpURLConnection
- 封裝OkHttp
WebView
WebView 可以在 應用程序中(而不是瀏覽器) 展示一些網頁。
布局文件 web_layout.xml
:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><WebViewandroid:id="@+id/web_view"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout>
活動文件:
public class WebActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.web_layout);WebView webView = findViewById(R.id.web_view);// 使WebView支持JavaScript腳本webView.getSettings().setJavaScriptEnabled(true);// 用當前WebView顯示網頁而不是瀏覽器webView.setWebViewClient(new WebViewClient());webView.loadUrl("https://www.bilibili.com/");}
}
要在 Android 中使用網絡技術是需要在 AndroidManifest.xml
中聲明權限的:
<uses-permission android:name="android.permission.INTERNET" />
運行結果:
HTTP
使用HttpURLConnection
布局文件 http_layout.xml
:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button_sendRequest"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="發送請求"/><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/response_text"android:layout_width="match_parent"android:layout_height="wrap_content"/></ScrollView></LinearLayout>
- ScrollView控件: 以滾動形式查看屏幕外的內容。
- TextView控件: 用以顯示服務器返回的數據。
活動文件:
public class HTTPActivity extends AppCompatActivity {private static final String TAG = "HTTPActivity";TextView responseText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.http_layout);Button button_sendRequest = findViewById(R.id.button_sendRequest);responseText = findViewById(R.id.response_text);button_sendRequest.setOnClickListener(v->{sendRequestWithHttpURLConnection();Log.e(TAG, "click over");});}private void sendRequestWithHttpURLConnection() {// 開啟子線程來發起網絡請求new Thread(new Runnable() {@Overridepublic void run() {HttpURLConnection connection = null;BufferedReader reader = null;try {URL url = new URL("https://www.csdn.net/");connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(8000);connection.setReadTimeout(8000);InputStream in = connection.getInputStream();Log.e(TAG, "get in");// 下面對獲取到的輸入流進行讀取reader = new BufferedReader(new InputStreamReader(in));StringBuilder response = new StringBuilder();String line;while((line = reader.readLine()) != null){response.append(line);}Log.e(TAG, "run: "+response.toString());// 安卓不允許在子線程中進行UI操作// 通過runOnUiThread切換為主線程,然后將結果顯示到界面中runOnUiThread(new Runnable() {@Overridepublic void run() {responseText.setText(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();}
}
運行結果:
使用OkHttp
OkHttp項目在github上的主頁地址
在 build.gradle (:app)
文件的 dependencies
中添加依賴:
// define a BOM and its versionimplementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))// define any required OkHttp artifacts without versionimplementation("com.squareup.okhttp3:okhttp")
活動文件:
public class HTTPActivity extends AppCompatActivity {private static final String TAG = "HTTPActivity";TextView responseText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.http_layout);Button button_sendRequest = findViewById(R.id.button_sendRequest);responseText = findViewById(R.id.response_text);button_sendRequest.setOnClickListener(v->{sendRequestWithOkHttp();Log.e(TAG, "click over");});}private void sendRequestWithOkHttp() {// 開啟子線程來發起網絡請求new Thread(new Runnable() {@Overridepublic void run() {try {OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url("https://www.bilibili.com").build();Log.e(TAG, "request: "+request);Response response = client.newCall(request).execute();Log.e(TAG, "response: "+response);String responseData = response.body().string();Log.e(TAG, "responseData: "+responseData);runOnUiThread(new Runnable() {@Overridepublic void run() {responseText.setText(responseData);}});} catch (IOException e) {e.printStackTrace();}}}).start();}
}
運行結果:
封裝網絡操作
封裝HttpURLConnection
如果在每個使用到網絡功能的地方都實現一遍發送HTTP請求的代碼無疑是繁瑣的。因此,不妨將常用的網絡操作寫成一個個靜態方法,并將它們都存儲在一個類中,如:
public class HttpUtil {private static final String TAG = "HttpUtil";public static String sendHttpRequest(String address){HttpURLConnection connection = null;try {URL url =new URL(address);connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(8000);connection.setReadTimeout(8000);connection.setDoInput(true);connection.setDoOutput(true);InputStream in = connection.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(in));StringBuilder response = new StringBuilder();String line;while((line = reader.readLine()) != null){response.append(line);}return response.toString();} catch (Exception e) {e.printStackTrace();return e.getMessage();} finally {if(connection != null){connection.disconnect();}}}
}
如此一來需要發送HTTP請求時即可如此實現:
String url = "https://www.bilibili.com";
String response = HttpUtil.sendHttpRequest(url);
但這仍有缺陷,sendHttpRequest()
方法內部并沒有使用子線程,這意味著調用該方法時主線程有可能被阻塞,網絡請求又是耗時操作,這對于運行效率而言無疑是種災難。
而如果只是簡單地在 sendHttpRequest()
方法中開啟一個線程來發起HTTP請求,那么所有的耗時邏輯都是在子線程里進行的,sendHttpRequest()
方法會在 服務器還沒來得及響應 的時候就執行結束了(子線程中的邏輯還沒有執行完,主線程中已經結束了對sendHttpRequest()
方法的調用)。
因此應該配以回調機制來接受回饋數據,定義一個接口:
public interface HttpCallbackListener {// 成功響應時回調,參數為服務器返回的數據void onFinish(String response);// 操作錯誤時回調void onError(Exception e);
}
然后修改 HttpUtil.java
:
public class HttpUtil {private static final String TAG = "HttpUtil";public static void sendHttpRequest(final String address, HttpCallbackListener listener){new Thread(new Runnable() {@Overridepublic void run() {HttpURLConnection connection = null;try {URL url =new URL(address);connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(8000);connection.setReadTimeout(8000);connection.setDoInput(true);connection.setDoOutput(true);InputStream in = connection.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(in));StringBuilder response = new StringBuilder();String line;while((line = reader.readLine()) != null){response.append(line);}// 子線程中無法通過 return 返回數據,應通過 onFinish 方法回調if(listener != null){listener.onFinish(response.toString());Log.e(TAG, "run: "+response.toString());}} catch (Exception e) {if(listener != null){listener.onError(e);Log.e(TAG, "run: Exception");}} finally {if(connection != null){connection.disconnect();}}}}).start();}
}
此時我們調用 sendHttpRequest()
方法時需要將 HttpCallbackListener 的實例傳入:
private void sendRequestWithOkHttp() {// 開啟子線程來發起網絡請求new Thread(new Runnable() {@Overridepublic void run() {String url = "https://www.baidu.com";HttpUtil.sendHttpRequest(url, new HttpCallbackListener() {@Overridepublic void onFinish(String response) {runOnUiThread(new Runnable() {@Overridepublic void run() {responseText.setText(response);}});}@Overridepublic void onError(Exception e) {Log.e(TAG, "onError: "+e);}});}}).start();}
運行結果:
封裝OkHttp
封裝關于HTTP的操作:
public class HttpUtil {private static final String TAG = "HttpUtil";public static void sendHttpRequest(final String address, okhttp3.Callback callback){OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(address).build();Log.e(TAG, "request: "+request);client.newCall(request).enqueue(callback);}
}
調用 HttpUtil.sendHttpRequest()
發送請求的方法:
// 開啟子線程來發起網絡請求,OkHttpprivate void sendRequestWithOkHttp(){new Thread(new Runnable() {@Overridepublic void run() {HttpUtil.sendHttpRequest("https://www.bilibili.com", new okhttp3.Callback(){@Overridepublic void onResponse(Call call, Response response) throws IOException {String responseData = response.body().string();runOnUiThread(new Runnable() {@Overridepublic void run() {responseText.setText(responseData);}});}@Overridepublic void onFailure(Call call, IOException e) {Log.e(TAG, "onError: "+e);}});}}).start();}
PS: 不論是使用 HttpURLConnection 還是 OkHttp,最終的回調接口都還是在子線程中,因此如果想要執行 UI 操作必須借助 runOnUiThread()
方法進行線程轉換。
運行結果: