OkHttp、Retrofit、RxJava:一文講清楚

一、okHttp的同步和異步請求

Call?是 OkHttp 的核心接口,代表一個已準備好執行的 HTTP 請求。它支持?同步?和?異步?兩種模式:

? ? ? ? enqueue——>okHttp異步

OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url("https://example.com").build();client.newCall(request).enqueue(new Callback() {@Overridepublic void onResponse(Call call, Response response) throws IOException {System.out.println("Response: " + response.body().string());}@Overridepublic void onFailure(Call call, IOException e) {System.err.println("Request failed: " + e.getMessage());}
});

????????execute——>同步請求

? ? ? ? 特點

  1. 阻塞線程
    請求發送后,當前線程會阻塞,直到服務器返回響應或超時。

  2. 直接返回結果
    通過?execute()?方法直接返回?Response?對象,無需回調。

  3. 線程管理
    不能在主線程中執行,否則會觸發?NetworkOnMainThreadException?異常。同步請求必須在后臺線程中執行,可以使用?ThreadExecutorService?或 RxJava 等工具管理線程。

  4. 資源釋放
    Response?對象實現了?Closeable?接口,使用?try-with-resources?語法確保資源釋放。

  5. 超時設置
    默認超時為 10 秒,可通過?OkHttpClient.Builder?自定義:

OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url("https://example.com").build();
try (Response response = client.newCall(request).execute()) {if (response.isSuccessful()) {System.out.println("Response: " + response.body().string());} else {System.err.println("Request failed: " + response.code());}
} catch (IOException e) {System.err.println("Request error: " + e.getMessage());
}

    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.execute(() -> {try (Response response = client.newCall(request).execute()) {if (response.isSuccessful()) {System.out.println
    特性同步請求(execute異步請求(enqueue
    線程阻塞阻塞當前線程,直到請求完成不阻塞線程,后臺執行
    結果獲取直接返回?Response?對象通過?Callback?回調處理結果
    線程管理需手動管理線程,避免主線程阻塞自動在后臺線程執行,主線程無影響
    適用場景需立即獲取結果的場景(如單元測試)需異步處理的場景(如網絡請求)

    二、okHttp+Rxjava

    Observable<Response> observable = Observable.create(emitter -> {Call call = client.newCall(request);call.enqueue(new Callback() {@Overridepublic void onResponse(Call call, Response response) {if (!emitter.isDisposed()) {emitter.onNext(response);emitter.onComplete();}}@Overridepublic void onFailure(Call call, IOException e) {if (!emitter.isDisposed()) {emitter.onError(e);}}});emitter.setCancellable(call::cancel);
    });observable.subscribeOn(Schedulers.io()) // 在 IO 線程執行.observeOn(AndroidSchedulers.mainThread()) // 在主線程處理結果.subscribe(new Observer<Response>() {@Overridepublic void onSubscribe(Disposable d) {// 訂閱時調用}@Overridepublic void onNext(Response response) {System.out.println("Response: " + response.body().string());}@Overridepublic void onError(Throwable e) {System.err.println("Error: " + e.getMessage());}@Overridepublic void onComplete() {// 請求完成時調用}});

    二、Retrofit 的同步與異步用法,用Call發起請求

    Retrofit 內部使用 OkHttp 作為 HTTP 客戶端,這意味著在 Retrofit 的配置中,你可以定制 OkHttp 的各種參數(如超時設置、攔截器等)。

    為了更好地支持異步編程,Retrofit 提供了 RxJava 的 CallAdapter。通過這個適配器,你可以讓 API 接口直接返回 Observable、Single 等 RxJava 類型,從而使用 RxJava 的強大操作符來處理請求結果和錯誤。

    public interface ApiService {@GET("users")Call<List<User>> getUsers();
    }
    Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/").addConverterFactory(GsonConverterFactory.create())  // 使用 Gson 進行 JSON 轉換.build();ApiService apiService = retrofit.create(ApiService.class);
    

    Retrofit同步請求

    ????????需在子線程中調用,否則會觸發?NetworkOnMainThreadException

    new Thread(new Runnable() {@Overridepublic void run() {try {Call<List<User>> call = apiService.getUsers();Response<List<User>> response = call.execute();if (response.isSuccessful() && response.body() != null) {List<User> users = response.body();// 處理返回的數據} else {Log.e("Retrofit", "Response error: " + response.code());}} catch (IOException e) {e.printStackTrace();}}
    }).start();
    

    Retrofit異步請求

    Call<List<User>> call = apiService.getUsers();
    call.enqueue(new Callback<List<User>>() {@Overridepublic void onResponse(Call<List<User>> call, Response<List<User>> response) {if (response.isSuccessful() && response.body() != null) {List<User> users = response.body();// 處理返回的數據,比如更新 UI} else {// 請求成功,但是服務器返回錯誤碼,比如 404、500 等Log.e("Retrofit", "Response error: " + response.code());}}@Overridepublic void onFailure(Call<List<User>> call, Throwable t) {// 請求失敗,比如網絡錯誤或解析錯誤Log.e("Retrofit", "Request failed", t);}
    });
    

    三、Retrofit + RxJava 的同步/異步與線程統一處理,用Observable發起請求

    Observable?是 RxJava 的響應式編程模型,用于處理異步數據流。其優勢包括:

    • 鏈式調用:通過操作符(如?mapflatMap)簡化復雜邏輯。
    • 線程調度:通過?subscribeOn?和?observeOn?控制線程切換。
    • 錯誤處理:通過?onErrorReturn?或?retry?實現容錯。

    同步請求

    public interface ApiService {@GET("users/{id}")Observable<User> getUserRx(@Path("id") int id); // 返回 Observable
    }apiService.getUserRx(1).subscribeOn(Schedulers.io()) // 指定請求線程.observeOn(Schedulers.io())   // 指定響應處理線程.blockingSubscribe(user -> {// 同步阻塞獲取結果});

    異步請求

    // 1. 定義 API 接口,使用 RxJava 的 Observable 作為返回類型
    public interface ApiService {@GET("users")Observable<List<User>> getUsers();
    }// 2. 配置 OkHttp 客戶端(可添加攔截器、日志打印等)
    OkHttpClient okHttpClient = new OkHttpClient.Builder()// 例如:添加日志攔截器// .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).build();// 3. 配置 Retrofit,同時添加 Gson 轉換器和 RxJava 適配器
    Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/").client(okHttpClient).addConverterFactory(GsonConverterFactory.create())          // JSON 數據解析.addCallAdapterFactory(RxJava2CallAdapterFactory.create())      // RxJava 適配器.build();// 4. 創建 API 服務實例
    ApiService apiService = retrofit.create(ApiService.class);// 5. 使用 RxJava 進行網絡請求
    apiService.getUsers().subscribeOn(Schedulers.io())                   // 在 IO 線程執行網絡請求.observeOn(AndroidSchedulers.mainThread())      // 在主線程處理返回結果.subscribe(users -> {// 成功回調,處理用戶數據}, throwable -> {// 錯誤回調,處理異常情況});
    

    方案線程管理代碼復雜度適用場景
    OkHttp 原生手動切換簡單請求、低耦合場景
    Retrofit 原生手動切換接口化請求、中等復雜度
    Retrofit+RxJava自動統一管理復雜異步流、高可維護性

    四、具體使用Retrofit+RxJava

    // 1. 定義服務接口
    public interface UserService {@POST("/user/{userId}/profile")Observable<BaseResponse<UserProfile>> updateProfile(@Path("userId") String userId,@Body ProfileParams params);
    }// 2. 發起請求
    NetworkApi.createService(UserService.class, ServiceType.User.name()).updateProfile("123", new ProfileParams("Kimi", "avatar.jpg")).compose(NetworkApi.applySchedulers()).subscribe(new BaseObserver<UserProfile>() {@Overridepublic void onSuccess(UserProfile profile) {// 更新UI}@Overridepublic void onBusinessError(int code, String msg) {// 顯示錯誤提示}});

    設計優勢

    • 責任鏈模式:每個方法專注單一職責(創建→配置→調度→響應)
    • 類型安全:通過泛型確保數據模型一致性
    • 異常隔離:BaseObserver集中處理網絡/業務異常
    • 線程透明:applySchedulers()隱藏線程切換細節

    該模式常見于需要支持多環境、多服務類型的現代移動應用架構,特別適合企業級應用開發中需要統一管理API請求的場景。

    這是典型的Retrofit+RxJava組合的網絡請求鏈式調用寫法,結合了工廠模式、建造者模式和響應式編程思想。其核心結構可分為四個關鍵部分:

    1.服務實例創建
    NetworkApi.createService(ApiService.class, ServiceType.License.name())
    • NetworkApi是自定義的工廠類,封裝了Retrofit實例的創建過程
    • createService()方法通過動態代理生成ApiService接口的實現類
    • ServiceType.License.name()指定服務類型,通常用于動態配置baseUrl(如區分認證服務、業務服務等)
    2.具體API操作
    .action(id, params)
    • action()對應ApiService接口中定義的端點方法:
    @POST("/api/{serviceType}/actions")
    Observable<BaseResponse<T>> action(@Path("serviceType") String serviceType,@Body ActionParams params
    );
    • id參數可能用于路徑替換(@Path注解),params作為請求體(@Body注解)
    3.線程調度組合
    .compose(NetworkApi.applySchedulers(...))
    • compose()是RxJava的操作符,統一應用線程切換規則
    • applySchedulers()典型實現:
    4.觀察者封裝
    new BaseObserver<BaseResponse<AccessConsentRecordDetailBean>>()
    • 自定義的BaseObserver處理通用邏輯:
    public abstract class BaseObserver<T> implements Observer<T> {@Overridepublic void onError(Throwable e) {// 統一錯誤處理(網絡異常、業務異常等)}@Overridepublic void onNext(T response) {if (response.isSuccess()) {onSuccess(response.getData());} else {onBusinessError(response.getCode(), response.getMessage());}}
    }

    五、Flowable與Observable

    FlowableObservable是RxJava中兩種核心的響應式數據流類型,結合Retrofit使用時需要根據具體場景進行選型。以下是兩者的核心區別及在Retrofit中的實踐建議:

    類型特性Retrofit集成場景
    Observable無背壓機制的異步數據流,支持同步/異步操作,適合輕量級請求簡單API調用(如獲取用戶信息、配置數據)
    Flowable支持背壓控制的響應式流,內置5種策略處理生產消費速度差異大文件傳輸、實時數據推送等高并發場景

    核心區別

    1.?背壓處理機制
    • Flowable
      通過BackpressureStrategy配置策略(ERROR/BUFFER/DROP/LATEST/MISSING),在Retrofit中處理大數據流時需顯式指定策略:
    @GET("api/sensor-data")
    Flowable<Data> getSensorData(@Query("deviceId") String id);  // 默認使用ERROR策略[5](@ref)
    • Observable
      無背壓控制,Retrofit接口直接返回Observable時需確保數據量可控,否則可能引發OOM
    2.?線程模型

    Flowable
    強制異步訂閱,Retrofit需配合subscribeOn(Schedulers.io())使用:

    api.getSensorData("DEV001").subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())

    Observable
    支持同步調用,適合快速響應的本地緩存查詢:

    @GET("api/profile")
    Observable<User> getUserProfile();  // 同步獲取用戶數據[9](@ref)
    3.?性能表現
    • Flowable
      因背壓檢測機制,吞吐量比Observable低約15-30%,但內存更安全
    • Observable
      無額外性能損耗,適合高頻低數據量請求(如按鈕點擊事件統計)
    4.集成實現
    • BUFFER:文件下載(需注意內存監控)
    Flowable.create(emitter -> {...}, BackpressureStrategy.BUFFER)
    • DROP:實時股票行情推送(丟棄過時數據)
    • LATEST:即時聊天消息(保留最新消息)
    5.錯誤處理對比
    • Observable需手動捕獲異常:
    .subscribe(data -> {...},error -> { // 需處理所有異常 }
    )
    • Flowable通過onBackpressureXXX操作符自動處理:
    .onBackpressureDrop(dropped -> log("丟棄數據:" + dropped))

    性能優化建議

    1. 混合使用策略
      對核心業務接口使用Flowable+BUFFER策略,非核心功能使用Observable

    2. 動態緩存控制
      通過rx2.buffer-size參數調整Flowable緩存池:

      System.setProperty("rx2.buffer-size", "256");  // 默認128[7](@ref)
    3. 生命周期管理
      使用CompositeDisposable統一釋放資源:

      CompositeDisposable disposables = new CompositeDisposable();disposables.add(api.getDataStream().subscribe(data -> {...}));

    通過合理選擇Flowable與Observable,可使Retrofit網絡層在保證穩定性的同時獲得最佳性能。可以在金融交易、物聯網等高頻場景優先采用Flowable,而在常規業務API中使用Observable以降低復雜度。

    本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
    如若轉載,請注明出處:http://www.pswp.cn/web/70692.shtml
    繁體地址,請注明出處:http://hk.pswp.cn/web/70692.shtml
    英文地址,請注明出處:http://en.pswp.cn/web/70692.shtml

    如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

    相關文章

    Redis分布式緩存面試題

    為什么使用分布式緩存&#xff1f; 1. 提升性能 降低延遲&#xff1a;將數據緩存在離應用更近的地方&#xff0c;減少數據訪問時間。減輕數據庫壓力&#xff1a;緩存頻繁訪問的數據&#xff0c;減少對后端數據庫的請求&#xff0c;提升系統響應速度。 2. 擴展性 水平擴展&a…

    基于阿里云PAI平臺快速部署DeepSeek大模型實戰指南

    一、DeepSeek大模型&#xff1a;企業級AI應用的新標桿 1.1 為什么選擇DeepSeek&#xff1f; 近期&#xff0c;DeepSeek系列模型憑借其接近GPT-4的性能和開源策略&#xff0c;成為全球開發者關注的焦點。在多項國際評測中&#xff0c;DeepSeek-R1模型在推理能力、多語言支持和…

    C++---了解STL

    上節學習了模板&#xff0c;那么就得談到C的標準模板庫STL。 C98&#xff1a;以模板方式重寫了C標準庫&#xff0c;引入了STL(標準模板庫)。 1.概念 STL(Standard template Libarary)標準模板庫&#xff1a;是C標準庫的重要組成部分&#xff0c;不僅是一個可復用的組件庫&am…

    分享幾款比較常用的接口測試工具

    首先&#xff0c;什么是接口呢&#xff1f; 接口一般來說有兩種&#xff0c;一種是程序內部的接口&#xff0c;一種是系統對外的接口。 系統對外的接口&#xff1a;比如你要從別的網站或服務器上獲取資源或信息&#xff0c;別人肯定不會把數據庫共享給你&#xff0c;他只能給你…

    Qt layout

    文章目錄 Qt layout**關鍵機制****驗證示例****常見誤區****最佳實踐****總結**關鍵點總結&#xff1a;示例代碼說明&#xff1a;結論&#xff1a; Qt layout 在 Qt 中&#xff0c;當調用 widget->setLayout(layout) 時&#xff0c;layout 的父對象會被自動設置為該 widget…

    flutter: table calendar筆記

    pub dev&#xff1a;table_calendar 3.2.0 我來詳細解釋 TableCalendar 是如何根據不同的 CalendarFormat 來顯示界面的。主要邏輯在 CalendarCore 中實現。 核心邏輯分為以下幾個部分&#xff1a; 頁面數量計算 - _getPageCount 方法根據不同格式計算總頁數&#xff1a; in…

    【C++】各個版本新的特性和改進

    C 語言自從其誕生以來&#xff0c;經歷了多個版本的更新&#xff0c;每個版本都引入了新的特性和改進&#xff0c;目的是提升語言的表達能力、性能、安全性以及開發效率。下面是各個主要版本&#xff08;從 C98 到 C20&#xff09;的一些關鍵特性。 C98 (1998年) ISO C 標準化…

    C++模板與STL七日斬:從工業編程到高效數據管理(工業項目)

    模板如何提升工業代碼復用性 實戰項目&#xff1a;創建通用【工業設備容器】模板類 類模板的定義與實例化模板參數默認值 #include <iostream> #include <string> using namespace std;template <typename T string> class IndustrialContainer { priva…

    sh腳本把服務器B,服務器C目錄的文件下載到服務器A目錄,添加開機自啟動并且一小時執行一次腳本

    腳本邏輯 第一次會下載,第二次比較如果有就不下載 文件已存在&#xff1a; 如果目標目錄中已經存在同名文件&#xff0c;rsync 會比較源文件和目標文件的大小和修改時間。 如果源文件和目標文件的大小和修改時間完全相同&#xff0c;rsync 會跳過該文件&#xff0c;不會重新下載…

    云手機如何進行經緯度修改

    云手機如何進行經緯度修改 云手機修改經緯度的方法因不同服務商和操作方式有所差異&#xff0c;以下是綜合多個來源的常用方法及注意事項&#xff1a; 通過ADB命令注入GPS數據&#xff08;適用于技術用戶&#xff09; 1.連接云手機 使用ADB工具連接云手機服務器&#xff0c;…

    透徹理解:方差、協方差、相關系數、協方差矩陣及其應用

    最近看了幾篇跨領域特征對齊方面的經典文獻&#xff0c;學者們搞了很多花樣&#xff0c;如有的提出一階統計特征對齊&#xff0c;有的提出二階統計特征對齊&#xff0c;有的學者提出高階統計特征對齊。 通俗而言&#xff0c;就是在統計特征層面對跨域特征進行對齊&#xff0c;…

    Unity基礎學習(二)

    二、Mono中的重要內容 1、延遲函數 &#xff08;1&#xff09;延遲函數定義 延遲執行的函數&#xff0c;可以設定要延遲執行的函數和具體延遲的時間 &#xff08;2&#xff09;延遲函數的使用 #region 1、延遲函數//函數&#xff1a;Invoke(函數名/字符串&#xff0c;延遲時…

    20250212:ZLKMedia 推流

    1:資料 快速開始 ZLMediaKit/ZLMediaKit Wiki GitHub GitHub - ZLMediaKit/ZLMediaKit: WebRTC/RTSP/RTMP/HTTP/HLS/HTTP-FLV/WebSocket-FLV/HTTP-TS/HTTP-fMP4/WebSocket-TS/WebSocket-fMP4/GB28181/SRT server and client framework based on C++11 文檔里面提供了各個系…

    Holoens2開發報錯記錄02_通過主機獲取彩色和深度數據流常見錯誤

    01.E1696 E1696 無法打開源文件 “stdio.h” 解決方法&#xff1a; 更新一下SDK 1&#xff09;打開Visual Studio Installer&#xff0c;點擊修改 2&#xff09;安裝詳細信息中自己系統對應的SDK&#xff0c;點擊修改即可 02.WinError 10060 方法來源 解決方法&#xff1a…

    【Qt之QQuickWidget】QML嵌入QWidget中

    由于我項目開始使用Widgets,換公司后直接使用QML開發&#xff0c;沒有了解過如何實現widget到qml過渡&#xff0c;恰逢面試時遇到一家公司希望從widget遷移到qml開發&#xff0c;詢問相關實現&#xff0c;一時語塞&#xff0c;很尷尬&#xff0c;粗略研究并總結下。 對qwidget嵌…

    從單片機的啟動說起一個單片機到點燈發生了什么下——使用GPIO點一個燈

    目錄 前言 HAL庫對GPIO的抽象 核心分析&#xff1a;HAL_GPIO_Init 前言 我們終于到達了熟悉的地方&#xff0c;對GPIO的初始化。經過漫長的鋪墊&#xff0c;我們終于歷經千辛萬苦&#xff0c;來到了這里。關于GPIO的八種模式等更加詳細的細節&#xff0c;由于只是點個燈&am…

    ESP32S3:解決RWDT無法觸發中斷問題,二次開發者怎么才能使用內部RTC看門狗中斷RWDT呢?

    目錄 基于ESP32S3:解決RWDT無法觸發中斷問題引言解決方案1. 查看報錯日志2. 分析報錯及一步一步找到解決方法3.小結我的源碼基于ESP32S3:解決RWDT無法觸發中斷問題 引言 在嵌入式系統中,RWDT(看門狗定時器)是確保系統穩定性的重要組件。然而,在某些情況下,RWDT可能無法…

    對計算機中緩存的理解和使用Redis作為緩存

    使用Redis作為緩存緩存例子緩存的引入 Redis緩存的實現 使用Redis作為緩存 緩存 ?什么是緩存&#xff0c;第一次接觸這個東西是在考研學習408的時候&#xff0c;計算機組成原理里面學習到Cache緩存&#xff0c;用于降低由于內存和CPU的速度的差異帶來的延遲。它是在CPU和內存…

    vue3的實用工具庫@vueuse/core

    1.什么是vueuse/core 是一個基于 ?Vue Composition API? 開發的實用工具庫&#xff0c;旨在通過封裝高頻功能為可復用的組合式函數&#xff08;Composables&#xff09;&#xff0c;簡化 Vue 應用的開發流程。 提供 ?200 開箱即用的函數?&#xff0c;覆蓋狀態管理、瀏覽器…

    基于SSM的《計算機網絡》題庫管理系統(源碼+lw+部署文檔+講解),源碼可白嫖!

    摘 要 《計算機網絡》題庫管理系統是一種新穎的考試管理模式&#xff0c;因為系統是用Java技術進行開發。系統分為三個用戶進行登錄并操作&#xff0c;分別是管理員、教師和學生。教師在系統后臺新增試題和試卷&#xff0c;學生進行在線考試&#xff0c;還能對考生記錄、錯題…