Android 网络请求:OkHttp + Retrofit + RxJava 工具类详解
前言
在 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,让我们的代码变得简洁、优雅。
二、添加依赖
首先,确保在你的 build.gradle 文件中添加 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 deviceInfoAPI(@Query("deviceName") String deviceName); @POST("pathUrl") Observable 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 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 headers; public BaseInterceptor(Map 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 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 getDeviceInfo(String deviceName) { return apiService.deviceInfoAPI(deviceName) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } public static Observable 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() { @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() { @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.Builder 创建 Retrofit 实例,并使用 create() 方法创建服务实例,使用该实例即可进行请求。
3.添加 OkHttp 拦截器 可以添加 OkHttp 拦截器来实现对请求进行拦截和修改,比如对请求头部添加认证信息、对请求参数进行加密等。
4.使用 RxJava 进行线程切换 使用 RxJava 进行线程切换可以避免在主线程中进行耗时操作而导致主线程卡顿,同时也方便地进行异步任务的处理。
5.封装网络请求工具类 可以将 Retrofit、OkHttp、RxJava 等技术封装到一个网络请求工具类中,方便地进行调用和维护。
综上所述,OkHttp + Retrofit + RxJava 工具类的结合可以方便地完成 Android 网络请求的任务,同时也可以提高请求的效率和可维护性。