Retrofit、OkHttp(层网络请求,拦截器处理 Header、缓存)、子线程处理相关事务
1.WebView
WebView可以在我们自己的应用程序中嵌入一个浏览器并且展示网页
新建一个项目,修改主活动布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
可以看到在布局中使用了WebView,修改MainActivity
package com.example.webviewtest;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
WebView webView = findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl("https://www.baidu.com");
}
}
MainActivity中,首先获取WebView实例,调用WebView的getSettings()方法可以设置一些浏览器的属性,调用setJavaScriptEnabled()方法来让WebView支持javaScript脚本。
调用WebView的setWebViewClient()方法,并传入一个WebViewClinet实例。这段代码的作用是,当需要从一个网页跳转到另一个网页时,我们希望目标王爷仍然在当前WebView中显示,而不是打开浏览器。
WebView的loadUrl()方法将网址传入,就可以展示网页的内容,这里就让我们来看一看百度的首页。
由于本程序使用了网络功能,所以需要申请权限
2使用HTTP协议访问网络
- HTTP 协议基础:客户端发请求,服务器返回数据,客户端解析处理,浏览器(含 WebView )依此工作。
- WebView 示例:向百度服务器发 HTTP 请求,服务器返回百度首页 HTML 代码,WebView 调用手机浏览器内核解析展示。
- WebView 特点与不足:后台处理发请求、收响应、解析数据、展示页面,因封装好,难直观看到 HTTP 协议工作过程,故需手动发请求深入理解 。
2.1使用HttpURLConnection
获取
HttpURLConnection
实例:通过new URL()
传入目标网络地址创建URL
对象,再调用openConnection()
方法并强转为HttpURLConnection
类型,得到其实例 。URL url = new URL("http://www.baidu.com"); HttpURLConnection connection = (HttpURLConnection) url.openConnection();
设置 HTTP 请求方法:得到实例后,可用
setRequestMethod()
设置,常用GET
(从服务器获取数据 )和POST
(向服务器提交数据 )。connection.setRequestMethod("GET");
定制连接参数:可通过
setConnectTimeout()
(设置连接超时 )、setReadTimeout()
(设置读取超时 )等方法,依据实际需求定制。connection.setConnectTimeout(8000); connection.setReadTimeout(8000);
获取与处理服务器响应:调用
getInputStream()
获取服务器返回的输入流,后续需读取流中数据;操作完成后,用disconnect()
关闭 HTTP 连接 。InputStream in = connection.getInputStream(); connection.disconnect();
示例:新建一个NetWorkTest项目
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/send_request"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发送请求" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/response_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
package com.example.networktest;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MainActivity extends AppCompatActivity implements View
.OnClickListener {
TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
View button = findViewById(R.id.send_request);
responseText = findViewById(R.id.response_text);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.send_request) {
sendRequestWithHttpURLConnection();
}
}
private void sendRequestWithHttpURLConnection(){
//开启线程来发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try{
URL url = new URL("https://www.baidu.com");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
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 (Exception e){
e.printStackTrace();
}
}
if (connection != null){
connection.disconnect();
}
}
}
}).start();
}
private void showResponse(final String response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//在UI线程中显示响应内容
responseText.setText(response);
}
});
}
}
请求成功
可以成功看到服务器返回给我们的HTML代码。
提交数据也很简单,只需要将Http请求的方法改成POST,并在获取输入流之前把要提交的数据写出即可。注意每条数据都要以键值对的形式存在,数据和数据之间用&隔开,比如我们想要向服务器提交用户名和密码,就可以
connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username = admin&password = 123456");
2.2使用OkHttp
现在时广大Android开发者的首选网络通信库。
在使用OKHttp之前需要在项目中添加OkHttp库的依赖。编辑app/build.gradle在dependencies闭包下添加
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:24.2.1'
testImplementation 'junit:junit:4.12'
implementation 'com.squareup.okhttp3:okhttp:3.4.1'
添加上述依赖自动下载两个库一个OkHttp,一个是Okio库,后者是前者通信的基础。
OkHttp 基本使用流程
创建客户端实例:通过
new OkHttpClient()
创建OkHttpClient
实例,作为发起请求的客户端。OkHttpClient client = new OkHttpClient();
构建请求对象(Request):利用
Request.Builder
构建Request
对象,可通过url()
方法设置目标网络地址,若为 POST 请求,还需构建RequestBody
存放参数,并用post()
方法传入。Request request = new Request.Builder() .url("http://www.baidu.com") .build();
发起请求并获取响应:调用
OkHttpClient
的newCall()
方法创建Call
对象,再调用execute()
发送请求,获取Response
响应对象,从响应对象中可提取服务器返回数据。Response response = client.newCall(request).execute(); String responseData = response.body().string();
GET 请求关键步骤:构建
Request
时用url()
设地址,无需额外参数体,直接发起请求获取响应。POST 请求关键步骤:先通过
FormBody.Builder
构建RequestBody
存放参数(如用户名、密码 ),再在Request.Builder
中用post()
方法传入该RequestBody
,之后流程同 GET 请求。// 构建请求参数体 RequestBody requestBody = new FormBody.Builder() .add("username", "admin") .add("password", "123456") .build(); // 构建包含 POST 参数的请求 Request request = new Request.Builder() .url("http://www.baidu.com") .post(requestBody) .build();
直接在前面的项目上做修改
package com.example.networktest;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okio.Okio;
public class MainActivity extends AppCompatActivity implements View
.OnClickListener {
TextView responseText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
View button = findViewById(R.id.send_request);
responseText = findViewById(R.id.response_text);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.send_request) {
sendRquestWithOkHttp();
}
}
private void sendRquestWithOkHttp() {
new Thread(new Runnable() {
@Override
public void run() {
try{
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://www.baidu.com")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
showResponse(responseData);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
private void sendRequestWithHttpURLConnection(){
//开启线程来发起网络请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
BufferedReader reader = null;
try{
URL url = new URL("https://www.baidu.com");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
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 (Exception e){
e.printStackTrace();
}
}
if (connection != null){
connection.disconnect();
}
}
}
}).start();
}
private void showResponse(final String response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//在UI线程中显示响应内容
responseText.setText(response);
}
});
}
}
这里并没有做太大的改动,添加一个sendRequestWithOkHttp()方法,用OkHttp 的方式来实现了之前的Http请求
同样得到结果。
3.Retrofit
准确来说,Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。
原因:网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装
App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作
在服务端返回数据之后,OkHttp 将原始的结果交给 Retrofit,Retrofit根据用户的需求对结果进行解析
使用介绍
步骤1:添加Retrofit库的依赖
compile 'com.squareup.retrofit2:retrofit:2.0.2'
步骤2:创建 接收服务器返回数据 的类
步骤3:创建 用于描述网络请求 的接口
步骤4:创建 Retrofit 实例
步骤5:创建 网络请求接口实例 并 配置网络请求参数
步骤6:发送网络请求(异步 / 同步)
步骤7:处理服务器返回的数据
学习
package com.example.networktest;
import java.util.List;
public class Translation1 {
private String type;
private int errorCode;
private int elapsedTime;
private List<List<TranslateResultBean>> translateResult;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public int getElapsedTime() {
return elapsedTime;
}
public void setElapsedTime(int elapsedTime) {
this.elapsedTime = elapsedTime;
}
public List<List<TranslateResultBean>> getTranslateResult() {
return translateResult;
}
public void setTranslateResult(List<List<TranslateResultBean>> translateResult) {
this.translateResult = translateResult;
}
public static class TranslateResultBean {
/**
* src : merry me
* tgt : 我快乐
*/
public String src;
public String tgt;
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public String getTgt() {
return tgt;
}
public void setTgt(String tgt) {
this.tgt = tgt;
}
}
}
package com.example.networktest;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
public interface PostRequest_Interface {
@POST("mtpe-individual/transText?aldtype=16047&ext_channel=Aldtype#/auto/zh")
@FormUrlEncoded
Call<Translation1> getCall(@Field("i") String targetSentence);
//采用@Post表示Post方法进行请求(传入部分url地址)
// 采用@FormUrlEncoded注解的原因:API规定采用请求格式x-www-form-urlencoded,即表单形式
// 需要配合@Field 向服务器提交需要的字段
}
package com.example.networktest;
import static android.content.ContentValues.TAG;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class PostRequest extends AppCompatActivity implements View.OnClickListener {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.send_request);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.send_request) {
request();
}
}
public void request() {
//步骤4:创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://fanyi.baidu.com/") // 设置 网络请求 Url
.addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
.build();
// 步骤5:创建 网络请求接口 的实例
PostRequest_Interface request = retrofit.create(PostRequest_Interface.class);
//对 发送请求 进行封装(设置需要翻译的内容)
Call<Translation1> call = request.getCall("I love you");
//步骤6:发送网络请求(异步)
call.enqueue(new Callback<Translation1>() {
//请求成功时回调
@Override
public void onResponse(Call<Translation1> call, Response<Translation1> response) {
// 步骤7:处理返回的数据结果:输出翻译的内容
Log.d(TAG, "onResponse: "+response.body().getTranslateResult().get(0).get(0).getTgt());
}
//请求失败时回调
@Override
public void onFailure(Call<Translation1> call, Throwable throwable) {
Log.d(TAG, "onFailure: "+throwable.getMessage());
}
});
}
}