Android网络请求,Retrofit,OKHttp学习
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"><WebViewandroid: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 {@Overrideprotected 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"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Buttonandroid:id="@+id/send_request"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>
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;@Overrideprotected 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);}@Overridepublic void onClick(View v) {if (v.getId() == R.id.send_request) {sendRequestWithHttpURLConnection();}}private void sendRequestWithHttpURLConnection(){//开启线程来发起网络请求new Thread(new Runnable() {@Overridepublic 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() {@Overridepublic 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;@Overrideprotected 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);}@Overridepublic void onClick(View v) {if (v.getId() == R.id.send_request) {sendRquestWithOkHttp();}}private void sendRquestWithOkHttp() {new Thread(new Runnable() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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")@FormUrlEncodedCall<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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);button = findViewById(R.id.send_request);button.setOnClickListener(this);}@Overridepublic 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>() {//请求成功时回调@Overridepublic void onResponse(Call<Translation1> call, Response<Translation1> response) {// 步骤7:处理返回的数据结果:输出翻译的内容Log.d(TAG, "onResponse: "+response.body().getTranslateResult().get(0).get(0).getTgt());}//请求失败时回调@Overridepublic void onFailure(Call<Translation1> call, Throwable throwable) {Log.d(TAG, "onFailure: "+throwable.getMessage());}});}}