前言
在 Android 开发中,使用 OkHttp、Retrofit 和 RxJava 结合进行网络请求是一种常见的做法。这样的组合可以帮助我们更轻松地处理网络请求和响应,并在异步操作中使用 RxJava 的强大功能。本文将详细介绍如何创建一个网络请求工具类。
一、OkHttp + Retrofit + RxJava简介
OkHttp的优点:
1.支持Http/1.1 Http/2 网络协议
2.支持GZIP, 可以压缩下载体积
3.响应缓存可以直接避免重复请求
4.高效、灵活;通过连接池,减少了请求延迟
5.共享Socket,减少对服务器的请求次数
Retrofit的优点
可以配置不同HTTP client来实现网络请求,如okhttp、httpclient等
将接口的定义与使用分离开来,实现结构。
支持多种返回数据解析的Converter可以快速进行数据转换。
因为容易和RxJava结合使用,所以对于异步请求,同步请求也不需要做额外的工作。
Retrofit是基于OKHttp
优点1:简化逻辑,解耦了各个模块操作,单一化
比如要嵌套请求的时候,这个时候用flatMap操作符就可以实现优雅的链式嵌套请求
优点2:简化代码
它的操作符封装了规则,我们用一个操作符就可以实现许多功能
比如要打包网络请求,这个时候用zip就可以打包数据源
优点3:操作符强大,可以实现各种功能
flatmap解决嵌套回调的问题;mergeWith()可以把不同异步操作合并
优点4:最方便的是线程切换
优点5:错处处理
只要有异常发生onError()一定会被调用,这极大的简化了错误处理。只需要在一个地方处理错误即可以
Rxjava+Retrofit+Okhttp的优点
第一点:灵活。Retrofit是一个基于Restful的网络请求库,自身对OkHttp进行了封装,支持URL动态变化,所以我们完全可以在Retrofit的基础上再次对OkHttp进行简单的封装,比如封装一个OkHttpInterceptor等等。
第二点:链式编程。其实这个也是用Retrofit核心点了,可能很多人对链式编程并不感冒,但是这种编程风格一定会越来越火,因为链式编程让逻辑变得更加简洁(注意是逻辑而不是代码),增加了代码的可读性。同时Retrofit支持了RxJava这个优雅的异步请求库(后面我会出一篇文章专门讲这个库),与其组成了完美的技术CP,让我们的代码变得简洁、优雅。
二、添加依赖
首先,确保在你的 文件中添加 OkHttp、Retrofit、RxJava 和 Gson 的依赖:
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'io.reactivex.rxjava3:rxjava:3.0.13'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
三、 创建网络请求接口
定义一个接口,其中包含 GET、POST 请求的定义。
import io.reactivex.rxjava3.core.Observable;
import okhttp3.RequestBody;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface ApiService {
@GET("pathUrl")
Observable<Object> deviceInfoAPI(@Query("deviceName") String deviceName);
@POST("pathUrl")
Observable<Object> userLoginAPI(@Body RequestBody requestBody);
}
pathUrl —> 表示请求的路径
deviceName —> 表示请求的路径参数
requestBody —> 表示请求的路径参数
Object —> 表示请求结果类型,可创建请求体实体类代替
四、创建 Retrofit 实例
创建 Retrofit 实例,并配置 OkHttp:
import java.util.concurrent.TimeUnit;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitClient {
private static final String BASE_URL = "https://test-***/";
private static Retrofit retrofit;
private static OkHttpClient mOkHttpClient;
private static final int TIMEOUT_CONNECT = 10;// 连接超时时间(秒)
private static final int TIMEOUT_READ = 30;// 读取超时时间(秒)
private static final int TIMEOUT_WRITE = 30; // 写入超时时间(秒)
private static final int MAX_IDLE_CONNECTIONS = 8; // 最大空闲连接数
private static final int KEEP_ALIVE_DURATION = 30;// 空闲连接保持时间(秒)
private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS; // 空闲连接保持时间单位
private static HashMap<String, String> headMap = new HashMap<>();//头部信息
private RetrofitClient() {
// Private constructor to prevent instantiation.
}
/**
* 获取 OkHttpClient 实例
* @return OkHttpClient 实例
*/
public static OkHttpClient getOkHttpClient() {
if (mOkHttpClient == null) {
//使用连接池,尽量保持TCP连接的复用,而不是立即关闭。
ConnectionPool connectionPool = new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALIVE_DURATION, KEEP_ALIVE_TIME_UNIT);
mOkHttpClient = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT_CONNECT, TimeUnit.SECONDS)
.readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
.writeTimeout(TIMEOUT_WRITE, TimeUnit.SECONDS)
.connectionPool(connectionPool)
.addInterceptor(new BaseInterceptor(headerMap))//添加头部信息
.build();
}
return mOkHttpClient;
}
public static Retrofit getInstance() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(getOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build();
}
return retrofit;
}
}
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* @Author: Su
* @Date: 2023/11/18
* @Description:
*/
public class BaseInterceptor implements Interceptor {
private Map<String, String> headers;
public BaseInterceptor(Map<String, String> headers) {
this.headers = headers;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request()
.newBuilder();
builder.addHeader("Content-Type", "application/json;charset=UTF-8").build();
if (headers != null && headers.size() > 0) {
Set<String> keys = headers.keySet();
for (String headerKey : keys) {
builder.addHeader(headerKey, headers.get(headerKey)).build();
}
}
return chain.proceed(builder.build());
}
}
五、创建网络请求工具类
创建一个网络请求工具类 NetworkUtils,封装具体的网络请求逻辑:
public class NetworkUtils {
private static final ApiService apiService = RetrofitClient.getInstance().create(ApiService.class);
private NetworkUtils() {
// Private constructor to prevent instantiation.
}
public static Observable<Object> getDeviceInfo(String deviceName) {
return apiService.deviceInfoAPI(deviceName)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
public static Observable<Object> userLoginResult(RequestBody requestBody) {
return apiService.userLoginAPI(requestBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
deviceName —> 表示请求的路径参数
requestBody —> 表示请求的路径参数
Object —> 表示请求结果类型,可创建请求体实体类代替
六、使用网络请求工具类
import android.util.Log;
import org.json.JSONObject;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.observers.DisposableObserver;
import okhttp3.MediaType;
import okhttp3.RequestBody;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NetworkUtils.getDeviceInfo("deviceName").safeSubscribe(new DisposableObserver<DeviceInfoBean>() {
@Override
public void onNext(@NonNull Object s) {
Log.e("onNext--->",String.valueOf(s));
}
@Override
public void onError(@NonNull Throwable e) {
Log.e("onError--->",String.valueOf(e.getMessage()));
}
@Override
public void onComplete() {
Log.e("onComplete--->","Complete");
}
});
JSONObject params = new JSONObject();
try {
params.put("userName","***");
params.put("password","***");
}catch (Exception e){
e.printStackTrace();
}
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),String.valueOf(params));
NetworkUtils.userLoginResult(requestBody).safeSubscribe(new DisposableObserver<LoginBean>() {
@Override
public void onNext(@NonNull Object loginBean) {
Log.e("onNext--->",String.valueOf(loginBean));
}
@Override
public void onError(@NonNull Throwable e) {
Log.e("onError--->",String.valueOf(e.getMessage()));
}
@Override
public void onComplete() {
Log.e("onComplete--->","Complete");
}
});
}
}
总结
OkHttp + Retrofit + RxJava 工具类的结合可以方便地完成 Android 网络请求的任务,以下是该工具类的总结:
1.定义 Retrofit 接口 在 Retrofit 接口中定义网络请求的方法,包括请求方法(GET/POST/PUT/DELETE等)、请求路径、请求参数、请求头部、返回类型等信息。
2.使用 Retrofit 创建服务 使用 创建 Retrofit 实例,并使用 create() 方法创建服务实例,使用该实例即可进行请求。
3.添加 OkHttp 拦截器 可以添加 OkHttp 拦截器来实现对请求进行拦截和修改,比如对请求头部添加认证信息、对请求参数进行加密等。
4.使用 RxJava 进行线程切换 使用 RxJava 进行线程切换可以避免在主线程中进行耗时操作而导致主线程卡顿,同时也方便地进行异步任务的处理。
5.封装网络请求工具类 可以将 Retrofit、OkHttp、RxJava 等技术封装到一个网络请求工具类中,方便地进行调用和维护。
综上所述,OkHttp + Retrofit + RxJava 工具类的结合可以方便地完成 Android 网络请求的任务,同时也可以提高请求的效率和可维护性。