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则是那个精准控制水温的咖啡机。现在,是时候用这些工具构建出属于你自己的美味代码了! ☕🚀

相关推荐
love_muming10 分钟前
二叉树操作全解析:从递归到层序遍历
java·数据结构·算法·二叉树
小的~~10 分钟前
ThreadLocal 、InheritableThreadLocal 与 TransmittableThreadLocal 的进阶指南
java·开发语言
北极糊的狐21 分钟前
钉钉小程序报错data.formatTime is not a function是因为 axml 模板中不能直接调用 Page 内自定义方法!
java·小程序·钉钉
·薯条大王9 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
ZJH__GO12 小时前
网络编程v4pro--实现聊天室文件传输功能
java·服务器·网络·计算机网络
程序员黑豆13 小时前
Windows 系统 Java 环境变量配置全攻略:解决“不是内部或外部命令”
java·前端·ai编程
命运之光13 小时前
【C语言完整代码】就诊信息管理系统
java·c语言·开发语言
凤山老林13 小时前
Spring Boot @Async 线上实战:从默认配置到生产级线程池治理
java·spring boot·后端
marvelyu14 小时前
每天10分钟学会OceanBase系列(Day 20):跨机房容灾实战——构建多数据中心高可用架构
java·大数据·数据库
AI人工智能+电脑小能手15 小时前
大白话说Java设计模式-04-工厂方法模式(业务实战篇)
java·设计模式·工厂方法模式·架构设计·代码解耦