目录
一、okhttp介绍
1. OkHttpClient类:
常用方法:
2. Request类:
常用方法:
3. Response类:
常用方法:
4. Call类:
常用方法:
5. Interceptor接口:
常用方法:
6. FormBody类:
常用方法:
7. MultipartBody类:
常用方法:
8. WebSocket类:
常用方法:
二、okhttp使用方法
1、添加依赖:
2、创建OkHttpClient对象:
3、创建Request对象:
4、发送同步请求:
5、发送异步请求
三、okhttp例子
省的json数据格式:
市的json数据格式:
县的json数据格式:
MainActivity:
Utility :
HttpTool :
Province :
City:
County :
activity_main:
litepal.xml:
AndroidManifest:
依赖:
运行结果:
一、okhttp介绍
OkHttp是一个开源的HTTP客户端库,常用于Android应用程序中进行网络请求。以下是OkHttp的一些常用类和方法:
1. OkHttpClient类:
OkHttpClient是OkHttp库的核心类,用于创建和配置HTTP请求的客户端。它提供了各种设置和配置选项,如连接超时、读写超时、拦截器等。
常用方法:
-
newBuilder()
:创建一个新的OkHttpClient.Builder实例,用于配置和构建OkHttpClient对象。 -
addInterceptor(Interceptor interceptor)
:添加一个Interceptor拦截器,用于在发送请求和接收响应时对其进行处理。例如,可以使用拦截器对请求进行身份验证、日志记录或数据转换等操作。 -
connectTimeout(long timeout, TimeUnit unit)
:设置连接超时时间。可以指定一个时间值和时间单位来限制与服务器建立连接的最长时间。 -
readTimeout(long timeout, TimeUnit unit)
:设置读取超时时间。可以指定一个时间值和时间单位来限制从服务器读取数据的最长时间。 -
writeTimeout(long timeout, TimeUnit unit)
:设置写入超时时间。可以指定一个时间值和时间单位来限制向服务器写入数据的最长时间。 -
retryOnConnectionFailure(boolean retry)
:设置是否重试连接失败的请求。默认情况下,OkHttpClient会自动重试请求,但可以通过该方法禁用重试。 -
followRedirects(boolean followRedirects)
:设置是否自动遵循重定向。默认情况下,OkHttpClient会自动遵循重定向,但可以通过该方法禁用自动重定向。 -
cache(Cache cache)
:设置缓存。可以传入一个Cache对象,用于缓存网络请求的响应数据。 -
dispatcher(Dispatcher dispatcher)
:设置Dispatcher调度器。可以传入一个自定义的Dispatcher对象,用于控制并发请求数量和线程池的行为。 -
proxy(Proxy proxy)
:设置代理服务器。可以指定一个Proxy对象,用于将请求通过代理发送到目标服务器。
2. Request类:
Request类用于构建HTTP请求。可以通过Request.Builder来创建一个Request对象,并设置URL、请求方法(GET、POST等)、请求头、请求体等。
常用方法:
-
newBuilder()
:创建一个新的Request.Builder实例,用于构建和配置Request对象。 -
url(String url)
:设置请求的URL地址。可以传入一个字符串类型的URL地址作为参数。 -
method(String method, RequestBody body)
:设置请求的HTTP方法和请求体。可以指定请求的HTTP方法(如GET、POST、PUT等)和请求体RequestBody对象。 -
header(String name, String value)
:添加请求头。可以通过该方法添加自定义的请求头参数,需要提供参数名和参数值。 -
headers(Headers headers)
:设置请求头集合。可以通过该方法一次性设置多个请求头,需要传入Headers对象。 -
cacheControl(CacheControl cacheControl)
:设置缓存控制策略。可以传入一个CacheControl对象,用于控制请求的缓存行为。 -
tag(Object tag)
:设置请求的标签。可以传入一个Object类型的标签,用于在后续操作中标识和识别该请求。 -
build()
:构建Request对象。在配置完成后,使用该方法来构建最终的Request对象。
3. Response类:
Response类表示HTTP响应。当发送HTTP请求后,可以通过Response对象获取服务器返回的响应信息,包括状态码、响应头、响应体等。
常用方法:
-
code()
:获取HTTP响应的状态码。返回一个整型值,表示HTTP响应的状态码。 -
message()
:获取HTTP响应的状态消息。返回一个字符串,表示HTTP响应的状态消息。 -
body()
:获取HTTP响应的响应体。返回一个ResponseBody对象,用于获取和处理响应的具体数据。 -
headers()
:获取HTTP响应的响应头。返回一个Headers对象,用于获取和处理响应的头部信息。 -
isSuccessful()
:判断HTTP响应是否成功。返回一个布尔值,表示HTTP响应是否成功(状态码在200-299之间)。 -
cacheResponse()
:获取缓存的HTTP响应。如果请求使用了缓存,并且有对应的缓存响应,则返回一个Response对象,否则返回null。 -
networkResponse()
:获取网络的HTTP响应。如果请求是通过网络发送的,并且有对应的网络响应,则返回一个Response对象,否则返回null。 -
priorResponse()
:获取前一个HTTP响应。如果请求有关联的前一个HTTP响应,则返回一个Response对象,否则返回null。 -
request()
:获取与该HTTP响应相关联的请求。返回一个Request对象,表示与该响应相关联的请求。
4. Call类:
Call类表示一个异步的HTTP请求任务。通过OkHttpClient的newCall方法创建一个Call对象,然后可以使用enqueue方法发送异步请求,并通过回调函数处理响应结果。
常用方法:
-
execute()
:同步执行HTTP请求并返回Response对象。该方法会阻塞当前线程,直到获取到完整的响应结果。 -
enqueue(Callback callback)
:异步执行HTTP请求并通过回调函数接收结果。该方法将请求放入请求队列中,并在后台线程执行,执行完成后通过Callback接口回调返回结果。 -
cancel()
:取消HTTP请求。如果HTTP请求尚未执行完毕,可以调用该方法取消正在进行的请求。 -
isExecuted()
:判断HTTP请求是否已经执行。返回一个布尔值,表示HTTP请求是否已经执行。 -
isCanceled()
:判断HTTP请求是否已经取消。返回一个布尔值,表示HTTP请求是否已经取消。 -
timeout()
:获取超时设置。返回一个Timeout对象,用于获取和设置连接、读取和写入的超时时间。 -
request()
:获取与该Call相关联的请求。返回一个Request对象,表示与该Call相关联的HTTP请求。 -
clone()
:创建Call对象的副本。返回一个新的Call对象,与原始的Call对象共享相同的配置和请求信息。
5. Interceptor接口:
Interceptor接口可以用于对HTTP请求和响应进行拦截和处理。可以实现自定义的Interceptor来对请求进行修改、添加请求头、记录日志等操作。
常用方法:
-
Response intercept(Chain chain)
:拦截并处理请求和响应。该方法接收一个Chain对象作为参数,可以通过该对象获取请求信息并执行下一个拦截器或者发起实际的网络请求。 -
interface Chain
:表示拦截器链中的一环,用于传递请求和响应以及控制拦截器的执行流程。Chain接口拥有以下方法:
Connection connection()
:获取当前拦截器链的连接对象。Request request()
:获取当前拦截器链的请求对象。Response proceed(Request request)
:执行下一个拦截器,并返回最终的响应结果。
6. FormBody类:
FormBody类是OkHttp库中用于构建表单形式的请求体的类。它提供了一些方法来添加表单字段和值,并生成最终的请求体数据。
常用方法:
-
add(String name, String value)
:添加表单字段和值。可以多次调用该方法,以添加多个表单字段和对应的值。 -
encodedName(int index)
:获取编码后的表单字段名。传入索引值,返回对应位置的编码后的表单字段名。 -
encodedValue(int index)
:获取编码后的表单字段值。传入索引值,返回对应位置的编码后的表单字段值。 -
name(int index)
:获取未编码的表单字段名。传入索引值,返回对应位置的未编码的表单字段名。 -
value(int index)
:获取未编码的表单字段值。传入索引值,返回对应位置的未编码的表单字段值。 -
size()
:获取表单字段的数量。返回一个整型值,表示表单字段的数量。 -
contentType()
:获取请求体的媒体类型。返回一个MediaType对象,表示请求体的媒体类型,默认为"application/x-www-form-urlencoded"。 -
contentLength()
:获取请求体的长度。返回一个长整型值,表示请求体的字节长度。 -
toString()
:将FormBody转换为字符串。返回一个字符串,表示FormBody的内容。
7. MultipartBody类:
MultipartBody类是OkHttp库中用于构建多部分(multipart)请求体的类。它允许在单个请求中包含多个不同类型的数据,如文本、文件等。
常用方法:
-
create(MediaType type, RequestBody... parts)
:创建一个MultipartBody对象。需要传入媒体类型和多个RequestBody实例。 -
type()
:获取请求体的媒体类型。返回一个MediaType对象,表示请求体的媒体类型,默认为"multipart/form-data"。 -
boundary()
:获取边界字符串。返回一个字符串,表示请求体的边界字符串。 -
contentType()
:获取请求体的完整媒体类型。返回一个字符串,表示请求体的完整媒体类型,包括媒体类型和边界字符串。 -
parts()
:获取请求体的各个部分。返回一个List<RequestBody>,表示请求体中的所有部分。 -
writeTo(BufferedSink sink)
:将MultipartBody写入到缓冲区。需要传入一个BufferedSink对象,用于写入请求体的数据。 -
contentLength()
:获取请求体的长度。返回一个长整型值,表示请求体的字节长度。 -
addPart(Headers headers, RequestBody body)
:添加一个部分到请求体中。可以传入自定义的请求头Headers对象和对应的RequestBody实例。 -
addFormDataPart(String name, @Nullable String filename, RequestBody body)
:添加一个表单数据部分到请求体中。需要传入字段名name、可选的文件名filename和RequestBody实例。 -
addFormDataPart(String name, @Nullable String filename, MediaType contentType, ByteString content)
:添加一个表单数据部分到请求体中。需要传入字段名name、可选的文件名filename、媒体类型contentType和内容content。
8. WebSocket类:
WebSocket类用于进行WebSocket通信。可以建立与服务器的WebSocket连接,并进行双向通信。
常用方法:
-
request()
:获取与该WebSocket相关联的请求。返回一个Request对象,表示与该WebSocket相关联的HTTP请求。 -
queueSize()
:获取待发送的消息队列大小。返回一个整型值,表示待发送的消息队列中的消息数量。 -
send(String text)
:发送文本消息。可以传入一个字符串类型的消息内容,将其作为文本消息发送给服务器。 -
send(ByteString bytes)
:发送二进制消息。可以传入一个ByteString对象,将其作为二进制消息发送给服务器。 -
close(int code, String reason)
:关闭WebSocket连接。可以传入一个整型的关闭码(如1000表示正常关闭)、一个字符串的关闭原因,以便向服务器发送关闭帧,并关闭WebSocket连接。 -
cancel()
:取消WebSocket连接。如果WebSocket连接尚未关闭,可以调用该方法取消连接。 -
send(Request request, WebSocketListener listener)
:发送指定请求的WebSocket消息。可以传入一个Request对象和一个WebSocketListener对象,将该请求发送给服务器,并通过WebSocketListener监听回调处理结果。 -
addListener(WebSocketListener listener)
:添加WebSocket事件监听器。可以传入一个WebSocketListener对象,用于监听WebSocket连接状态、收到消息等事件。 -
removeListener(WebSocketListener listener)
:移除WebSocket事件监听器。可以传入一个WebSocketListener对象,将其从WebSocket的监听器列表中移除。
二、okhttp使用方法
1、添加依赖:
在项目的build.gradle文件中添加OkHttp的依赖项。
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
2、创建OkHttpClient对象:
通过new OkHttpClient()
创建一个OkHttpClient实例,用于发送HTTP请求。
OkHttpClient client = new OkHttpClient();
3、创建Request对象:
使用Request.Builder
构建一个请求对象,并指定URL地址、请求头、请求体等相关信息。
Request request = new Request.Builder()
.url("https://example.com/api")
.header("Content-Type", "application/json")
.post(RequestBody.create(MediaType.parse("application/json"), jsonBody))
.build();
4、发送同步请求:
使用client.newCall(request).execute()
发送同步请求,并获得Response对象。
try (Response response = client.newCall(request).execute()) {
// 处理响应结果
if (response.isSuccessful()) {
String responseBody = response.body().string();
// ...
} else {
// 请求失败处理
}
} catch (IOException e) {
// IO异常处理
}
5、发送异步请求
使用client.newCall(request).enqueue(Callback)
发送异步请求,并通过Callback回调处理响应结果。
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 请求失败处理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 处理响应结果
if (response.isSuccessful()) {
String responseBody = response.body().string();
// ...
} else {
// 请求失败处理
}
}
});
在以上示例中,我们首先创建了一个OkHttpClient对象,并使用Request.Builder构建了一个请求对象。然后,可以选择性地发送同步或异步请求。对于同步请求,直接调用execute()
方法并处理响应结果;对于异步请求,使用enqueue(Callback)
方法并通过Callback回调处理响应结果。
当处理完请求后,需要注意关闭Response对象的资源,以避免内存泄漏。
三、okhttp例子
下面例子是郭霖大神的第一行代码中的酷欧天气网络请求地名的代码。
省的json数据格式:
http://guolin.tech/api/china
市的json数据格式:
http://guolin.tech/api/china/16
县的json数据格式:
MainActivity:
package com.example.okhttpdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.okhttpdemo.Bean.City;
import com.example.okhttpdemo.Bean.County;
import com.example.okhttpdemo.Bean.Province;
import org.litepal.LitePal;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
import okhttp3.internal.Util;
public class MainActivity extends AppCompatActivity {
public static final int CURRENT_PAGE_PROVINCE = 0;
public static final int CURRENT_PAGE_CITY = 1;
public static final int CURRENT_PAGE_COUNTY = 2;
private List<Province> mProvinces;
private List<City> mCities;
private List<County> mCounties;
private TextView titleTV;
private Button backBtn;
private ListView mListView;
private List<String> mListData = new ArrayList<>();
private ArrayAdapter<String> mAdapter;
private ProgressDialog progressDialog;
private int currentPage;
private Province mCurrentProvince;
private City mCurrentCity;
private County mCurrentCounty;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LitePal.initialize(this);
initView();
}
private void initView() {
mListView = findViewById(R.id.list_view);
backBtn = findViewById(R.id.back_button);
titleTV= findViewById(R.id.title_text);
backBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (currentPage==CURRENT_PAGE_COUNTY){
queryCities();
}else if(currentPage == CURRENT_PAGE_CITY){
queryProvinces();
}
}
});
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (currentPage){
case CURRENT_PAGE_PROVINCE:
mCurrentProvince = mProvinces.get(position);
queryCities();
break;
case CURRENT_PAGE_CITY:
mCurrentCity = mCities.get(position);
queryCounty();
break;
case CURRENT_PAGE_COUNTY:
mCurrentCounty = mCounties.get(position);
Toast.makeText(MainActivity.this,"点击了"+mCurrentProvince.getProvinceName()+mCurrentCity.getCityName()+mCurrentCounty.getCountyName(),Toast.LENGTH_LONG).show();
break;
}
}
});
mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mListData);
queryProvinces();
mListView.setAdapter(mAdapter);
}
private void queryProvinces(){
titleTV.setText("中国");
backBtn.setVisibility(View.GONE);
// 从数据库中找
mProvinces = LitePal.findAll(Province.class);
if (mProvinces.size()>0){
mListData.clear();
for (Province province:mProvinces){
mListData.add(province.getProvinceName());
}
mAdapter.notifyDataSetChanged();
currentPage = CURRENT_PAGE_PROVINCE;
}else {
String url = "http://guolin.tech/api/china";
queryFromServer(url,CURRENT_PAGE_PROVINCE);
}
}
private void queryFromServer(String url, int type) {
showProgressDialog();
HttpTool.sendOkhttpRequest(url, new Callback() {
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
Toast.makeText(MainActivity.this,"加载失败!!!",Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onResponse(Call call, Response response) throws IOException {
boolean result = false;
switch (type){
case CURRENT_PAGE_PROVINCE:
result = Utility.handleProvinceResponse(response.body().string());
break;
case CURRENT_PAGE_CITY:
result = Utility.handleCitiesResponse(response.body().string(),mCurrentProvince.getId());
break;
case CURRENT_PAGE_COUNTY:
result = Utility.handleCountyResponse(response.body().string(),mCurrentCity.getId());
break;
}
if (result){
runOnUiThread(new Runnable() {
@Override
public void run() {
closeProgressDialog();
switch (type){
case CURRENT_PAGE_PROVINCE:
queryProvinces();
break;
case CURRENT_PAGE_CITY:
queryCities();
break;
case CURRENT_PAGE_COUNTY:
queryCounty();
break;
}
}
});
}
}
});
}
private void queryCounty() {
titleTV.setText(mCurrentCity.getCityName());
backBtn.setVisibility(View.VISIBLE);
// 从数据库中找
mCounties = LitePal.where("cityid=?",String.valueOf(mCurrentCity.getId())).find(County.class);
if (mCounties.size()!=0){
mListData.clear();
for (County county:mCounties){
mListData.add(county.getCountyName());
}
mAdapter.notifyDataSetChanged();
currentPage = CURRENT_PAGE_COUNTY;
}else {
int provinceCode = mCurrentProvince.getProvinceCode();
int citiCode = mCurrentCity.getCityCode();
String url = "http://guolin.tech/api/china/" + provinceCode+"/"+citiCode;
queryFromServer(url,CURRENT_PAGE_COUNTY);
}
}
private void queryCities() {
titleTV.setText(mCurrentProvince.getProvinceName());
backBtn.setVisibility(View.VISIBLE);
// 从数据库中找
mCities = LitePal.where("provinceid=?",String.valueOf(mCurrentProvince.getId())).find(City.class);
if (mCities.size()!=0){
mListData.clear();
for (City city:mCities){
mListData.add(city.getCityName());
}
mAdapter.notifyDataSetChanged();
currentPage = CURRENT_PAGE_CITY;
}else {
int provinceCode = mCurrentProvince.getProvinceCode();
String url = "http://guolin.tech/api/china/" + provinceCode;
queryFromServer(url,CURRENT_PAGE_CITY);
}
}
/**
* 显示进度对话框
*/
private void showProgressDialog() {
if (progressDialog == null) {
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("正在加载...");
progressDialog.setCanceledOnTouchOutside(false);
}
progressDialog.show();
}
/**
* 关闭进度对话框
*/
private void closeProgressDialog() {
if (progressDialog != null) {
progressDialog.dismiss();
}
}
}
Utility :
package com.example.okhttpdemo;
import android.text.TextUtils;
import com.example.okhttpdemo.Bean.City;
import com.example.okhttpdemo.Bean.County;
import com.example.okhttpdemo.Bean.Province;
import com.google.gson.Gson;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Utility {
/**
* 解析和处理服务器返回的省级的数据
*/
public static boolean handleProvinceResponse(String response) {
if (!TextUtils.isEmpty(response)) {
try {
JSONArray allProvinces = new JSONArray(response);
for (int i = 0; i < allProvinces.length(); i++) {
JSONObject provinceObject = allProvinces.getJSONObject(i);
Province province = new Province();
province.setProvinceName(provinceObject.getString("name"));
province.setProvinceCode(provinceObject.getInt("id"));
province.save();
}
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
/**
* 解析和处理服务器返回的市级的数据
*/
public static boolean handleCitiesResponse(String response,int provinceId){
if (!TextUtils.isEmpty(response)){
try {
JSONArray allCities = new JSONArray(response);
for (int i = 0; i < allCities.length() ; i++) {
JSONObject cityObject = allCities.getJSONObject(i);
City city = new City();
city.setCityName(cityObject.getString("name"));
city.setCityCode(cityObject.getInt("id"));
city.setProvinceId(provinceId);
city.save();
}
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
/**
* 解析和处理服务器返回的县级的数据
*/
public static boolean handleCountyResponse(String response,int cityId){
if (!TextUtils.isEmpty(response)){
try {
JSONArray allCounties = new JSONArray(response);
for (int i = 0; i < allCounties.length() ; i++) {
JSONObject countryObject = allCounties.getJSONObject(i);
County country = new County();
country.setCountyName(countryObject.getString("name"));
country.setWeatherId(countryObject.getString("weather_id"));
country.setCityId(cityId);
country .save();
}
return true;
} catch (JSONException e) {
e.printStackTrace();
}
}
return false;
}
}
HttpTool :
package com.example.okhttpdemo;
import okhttp3.OkHttpClient;
import okhttp3.Request;
public class HttpTool {
/**
*
* @param address 接口地址URL
* @param callback
*/
public static void sendOkhttpRequest(String address,okhttp3.Callback callback){
// 1、创建OkHttpClient对象
OkHttpClient client = new OkHttpClient();
// 2、创建Request对象
Request request = new Request.Builder().url(address).build();
// 3、发送异步请求
client.newCall(request).enqueue(callback);
}
}
Province :
package com.example.okhttpdemo.Bean;
import org.litepal.crud.LitePalSupport;
public class Province extends LitePalSupport {
private int id;
private String provinceName;
private int provinceCode;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getProvinceName() {
return provinceName;
}
public void setProvinceName(String provinceName) {
this.provinceName = provinceName;
}
public int getProvinceCode() {
return provinceCode;
}
public void setProvinceCode(int provinceCode) {
this.provinceCode = provinceCode;
}
}
City:
package com.example.okhttpdemo.Bean;
import org.litepal.crud.LitePalSupport;
public class City extends LitePalSupport {
private int id;
private String cityName;
private int cityCode;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public int getCityCode() {
return cityCode;
}
public void setCityCode(int cityCode) {
this.cityCode = cityCode;
}
public int getProvinceId() {
return provinceId;
}
public void setProvinceId(int provinceId) {
this.provinceId = provinceId;
}
private int provinceId;
}
County :
package com.example.okhttpdemo.Bean;
import org.litepal.crud.LitePalSupport;
public class County extends LitePalSupport {
private int id;
private String countyName;
private String weatherId;
private int cityId;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCountyName() {
return countyName;
}
public void setCountyName(String countyName) {
this.countyName = countyName;
}
public String getWeatherId() {
return weatherId;
}
public void setWeatherId(String weatherId) {
this.weatherId = weatherId;
}
public int getCityId() {
return cityId;
}
public void setCityId(int cityId) {
this.cityId = cityId;
}
}
activity_main:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#7283DD"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/teal_200">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/title_text"
android:layout_centerInParent="true"
android:textColor="#fff"
android:textSize="20sp"/>
<Button
android:id="@+id/back_button"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:background="@drawable/back"
/>
</RelativeLayout>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
litepal.xml:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value = "okhttpdemo"/>
<version value = "1"/>
<list>
<mapping class = "com.example.okhttpdemo.Bean.Province"/>
<mapping class = "com.example.okhttpdemo.Bean.City"/>
<mapping class = "com.example.okhttpdemo.Bean.County"/>
</list>
</litepal>
AndroidManifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.okhttpdemo">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:networkSecurityConfig="@xml/network_security_config"
android:name = "org.litepal.LitePalApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
依赖:
implementation("com.squareup.okhttp3:okhttp:3.4.1")
implementation 'org.litepal.guolindev:core:3.2.3'
implementation 'com.google.code.gson:gson:2.7'