Retrofit+RxJava:打造声明式REST客户端的艺术 —— 像点咖啡一样调用API

目录

场景漫游:想象你在星巴克告诉咖啡师"一杯中杯拿铁,加燕麦奶,75度",后端服务调用API也该如此优雅!今天我们将用Retrofit+RxJava这对黄金组合,实现比咖啡订单更丝滑的API调用体验。


一、告别Callback地狱:声明式编程的魅力

1.1 传统网络请求的痛点

java 复制代码
// 传统回调地狱案例
apiService.getUser(userId, new Callback<User>() {
    @Override
    public void onResponse(Call<User> call, Response<User> response) {
        if (response.isSuccessful()) {
            apiService.getOrders(response.body().getId(), new Callback<List<Order>>() {
                @Override
                public void onResponse(Call<List<Order>> call, Response<List<Order>> response) {
                    // 处理订单数据...
                }
                // 省略错误处理...
            });
        }
    }
    // 省略错误处理...
});

灾难现场

🌀 嵌套金字塔结构

🕳️ 错误处理分散

⏳ 线程切换复杂

1.2 Retrofit的声明式革命

java 复制代码
public interface GitHubService {
    @GET("users/{user}/repos")
    Observable<List<Repo>> listRepos(@Path("user") String user);
}

魔法解析

✅ 接口即文档

✅ 参数注解自动拼接URL

✅ 返回值类型自由定义(支持RxJava类型)


二、Retrofit核心配置工厂

2.1 构建Retrofit实例

java 复制代码
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create()) // JSON转换
    .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) // RxJava支持
    .client(new OkHttpClient.Builder()
        .addInterceptor(new HttpLoggingInterceptor()) // 请求日志
        .connectTimeout(10, TimeUnit.SECONDS)
        .build())
    .build();

2.2 常用注解速查表

注解 作用示例 对应HTTP元素
@GET @GET("users/{id}") GET请求
@Path @Path("id") Long userId URL路径参数
@Query @Query("sort") String sort URL查询参数
@Body @Body LoginRequest request 请求体
@Header @Header("Authorization") 请求头

三、RxJava响应式魔法

3.1 链式调用优雅变身

java 复制代码
// 获取用户资料后获取最新动态
apiService.getUserProfile(userId)
    .flatMap(user -> apiService.getLatestActivities(user.getId()))
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(
        activities -> showActivities(activities),
        error -> showError(error)
    );

操作符流程图

复制代码
(GetUser) → (FlatMap) → (GetActivities) → (UI展示)

3.2 超能力操作符盘点

java 复制代码
// 并行请求用户信息和订单列表
Observable.zip(
    apiService.getUserInfo(userId),
    apiService.getUserOrders(userId),
    (userInfo, orders) -> new UserDashboard(userInfo, orders)
).subscribe(dashboard -> updateUI(dashboard));

// 带超时和重试的请求
apiService.fetchData()
    .timeout(5, TimeUnit.SECONDS)
    .retryWhen(errors -> errors.flatMap(error -> {
        if (error instanceof SocketTimeoutException) {
            return Observable.timer(1, TimeUnit.SECONDS);
        }
        return Observable.error(error);
    }))
    .subscribe(...);

四、实战演练:构建天气查询客户端

4.1 定义天气接口

java 复制代码
public interface WeatherService {
    @GET("weather")
    Observable<WeatherData> getWeatherByCity(
        @Query("q") String city,
        @Query("appid") String apiKey
    );
}

4.2 ViewModel中集成

java 复制代码
public class WeatherViewModel extends ViewModel {
    private final CompositeDisposable disposables = new CompositeDisposable();

    public void loadWeather(String city) {
        disposables.add(weatherService.getWeatherByCity(city, API_KEY)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSubscribe(d -> loadingState.setValue(true))
            .doFinally(() -> loadingState.setValue(false))
            .subscribe(
                data -> weatherData.postValue(data),
                error -> showError(error)
            ));
    }

    @Override
    protected void onCleared() {
        disposables.clear();
    }
}

4.3 动态更新UI

xml 复制代码
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    onRefresh="刷新天气数据">

    <TextView
        android:id="@+id/tvTemperature"
        android:text="@{viewModel.weatherData.temp}℃" />
    
    <ImageView
        android:src="@{viewModel.weatherData.getWeatherIcon()}" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

五、高级技巧:错误处理艺术

5.1 全局错误拦截器

java 复制代码
public class GlobalErrorInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Response response = chain.proceed(chain.request());
        if (!response.isSuccessful()) {
            throw new HttpException(response.code(), response.message());
        }
        return response;
    }
}

// 注入OkHttpClient
new OkHttpClient.Builder()
    .addInterceptor(new GlobalErrorInterceptor())

5.2 响应统一包装

java 复制代码
public class ApiResponse<T> {
    private T data;
    private Throwable error;
    
    public Observable<ApiResponse<T>> wrap(Observable<T> origin) {
        return origin
            .map(data -> new ApiResponse<>(data))
            .onErrorReturn(error -> new ApiResponse<>(error));
    }
}

// 使用示例
apiService.fetchData()
    .compose(new ApiResponseWrapper())
    .subscribe(response -> {
        if (response.hasError()) {
            // 处理错误
        } else {
            // 处理数据
        }
    });

六、性能优化实战指南

6.1 请求缓存策略

java 复制代码
// 缓存控制拦截器
public class CacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        if (NetworkUtils.isNetworkAvailable()) {
            request = request.newBuilder()
                .header("Cache-Control", "public, max-age=60")
                .build();
        } else {
            request = request.newBuilder()
                .header("Cache-Control", 
                    "public, only-if-cached, max-stale=604800")
                .build();
        }
        return chain.proceed(request);
    }
}

6.2 合并重复请求

java 复制代码
// 使用RxJava的cache()操作符
Observable<List<Product>> productsObservable = apiService.getProducts()
    .cache()
    .subscribeOn(Schedulers.io());

// 多个订阅者共享结果
productsObservable.subscribe(products -> updateList(products));
productsObservable.subscribe(products -> updateChart(products));

七、你该这样思考:架构师的视角

当你熟练使用Retrofit+RxJava后,可以尝试:

  1. 封装统一网络层模块
  2. 实现自动Token刷新机制
  3. 与Kotlin协程结合使用
  4. 编写API Mock测试模块
  5. 实施流量监控与报警

站在咖啡店的落地窗前,看着自己构建的声明式API客户端------它就像一杯精心调制的咖啡,每个操作符都是独特的调味剂,而Retrofit则是那个精准控制水温的咖啡机。现在,是时候用这些工具构建出属于你自己的美味代码了! ☕🚀

相关推荐
云原生指北2 小时前
GitHub Copilot SDK 入门:五分钟构建你的第一个 AI Agent
java
Leinwin6 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
薛定谔的悦6 小时前
MQTT通信协议业务层实现的完整开发流程
java·后端·mqtt·struts
enjoy嚣士7 小时前
springboot之Exel工具类
java·spring boot·后端·easyexcel·excel工具类
罗超驿7 小时前
独立实现双向链表_LinkedList
java·数据结构·链表·linkedlist
盐水冰8 小时前
【烘焙坊项目】后端搭建(12) - 订单状态定时处理,来单提醒和顾客催单
java·后端·学习
凸头8 小时前
CompletableFuture 与 Future 对比与实战示例
java·开发语言
wuqingshun3141598 小时前
线程安全需要保证几个基本特征
java·开发语言·jvm
努力也学不会java8 小时前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
攒了一袋星辰8 小时前
高并发强一致性顺序号生成系统 -- SequenceGenerator
java·数据库·mysql