目录
-
- 一、告别Callback地狱:声明式编程的魅力
-
- [1.1 传统网络请求的痛点](#1.1 传统网络请求的痛点)
- [1.2 Retrofit的声明式革命](#1.2 Retrofit的声明式革命)
- 二、Retrofit核心配置工厂
-
- [2.1 构建Retrofit实例](#2.1 构建Retrofit实例)
- [2.2 常用注解速查表](#2.2 常用注解速查表)
- 三、RxJava响应式魔法
-
- [3.1 链式调用优雅变身](#3.1 链式调用优雅变身)
- [3.2 超能力操作符盘点](#3.2 超能力操作符盘点)
- 四、实战演练:构建天气查询客户端
-
- [4.1 定义天气接口](#4.1 定义天气接口)
- [4.2 ViewModel中集成](#4.2 ViewModel中集成)
- [4.3 动态更新UI](#4.3 动态更新UI)
- 五、高级技巧:错误处理艺术
-
- [5.1 全局错误拦截器](#5.1 全局错误拦截器)
- [5.2 响应统一包装](#5.2 响应统一包装)
- 六、性能优化实战指南
-
- [6.1 请求缓存策略](#6.1 请求缓存策略)
- [6.2 合并重复请求](#6.2 合并重复请求)
- 七、你该这样思考:架构师的视角
☕ 场景漫游:想象你在星巴克告诉咖啡师"一杯中杯拿铁,加燕麦奶,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后,可以尝试:
- 封装统一网络层模块
- 实现自动Token刷新机制
- 与Kotlin协程结合使用
- 编写API Mock测试模块
- 实施流量监控与报警
站在咖啡店的落地窗前,看着自己构建的声明式API客户端------它就像一杯精心调制的咖啡,每个操作符都是独特的调味剂,而Retrofit则是那个精准控制水温的咖啡机。现在,是时候用这些工具构建出属于你自己的美味代码了! ☕🚀