将Google的NetworkBoundResource类重构为使用RxJava替代LiveData
嘿,关于Android架构组件里抽象网络数据获取逻辑的NetworkBoundResource,我来给你详细拆解下——这可是构建响应式网络请求的核心框架,用LiveData实现了一套完整的缓存读取→网络判断→数据同步的标准化流程,能帮你大幅减少重复的网络请求代码。
核心实现代码
首先放完整的抽象类代码(补全了你提供的片段):
import androidx.lifecycle.LiveData; import androidx.lifecycle.MediatorLiveData; import java.util.Objects; public abstract class NetworkBoundResource<ResultType, RequestType> { private final AppExecutors appExecutors; private final MediatorLiveData<Resource<ResultType>> result = new MediatorLiveData<>(); protected NetworkBoundResource(AppExecutors appExecutors) { this.appExecutors = appExecutors; init(); } private void init() { // 先发送加载状态给UI层 result.setValue(Resource.loading(null)); // 第一步:读取本地数据库缓存 LiveData<ResultType> dbSource = loadFromDb(); result.addSource(dbSource, data -> { result.removeSource(dbSource); if (shouldFetch(data)) { // 缓存数据不足/过期,发起网络请求 fetchFromNetwork(dbSource); } else { // 直接使用缓存数据,发送成功状态 result.addSource(dbSource, newData -> setValue(Resource.success(newData))); } }); } private void fetchFromNetwork(final LiveData<ResultType> dbSource) { // 发起具体的网络请求(由子类实现) LiveData<ApiResponse<RequestType>> apiResponse = createCall(); // 添加网络请求作为数据源 result.addSource(apiResponse, response -> { result.removeSource(apiResponse); result.removeSource(dbSource); if (response.isSuccessful()) { // 网络请求成功:先存数据库,再更新UI appExecutors.diskIO().execute(() -> { saveCallResult(processResponse(response)); // 切回主线程,读取更新后的缓存数据 appExecutors.mainThread().execute(() -> result.addSource(loadFromDb(), newData -> setValue(Resource.success(newData))) ); }); } else { // 网络请求失败:回调错误,同时保留缓存数据展示 onFetchFailed(); result.addSource(dbSource, newData -> setValue(Resource.error(response.errorMessage, newData))); } }); } private void setValue(Resource<ResultType> newValue) { // 避免重复发送相同状态 if (!Objects.equals(result.getValue(), newValue)) { result.setValue(newValue); } } // ---------------------- 子类需实现的抽象方法 ---------------------- // 从本地数据库读取缓存数据 protected abstract LiveData<ResultType> loadFromDb(); // 判断是否需要发起网络请求(比如缓存为空、过期) protected abstract boolean shouldFetch(ResultType data); // 创建具体的网络请求(比如Retrofit Call转LiveData) protected abstract LiveData<ApiResponse<RequestType>> createCall(); // 将网络返回的数据保存到本地数据库 protected abstract void saveCallResult(RequestType item); // 预处理网络响应(比如从Response中提取实体类) protected abstract RequestType processResponse(ApiResponse<RequestType> response); // 网络请求失败的回调(可选实现) protected void onFetchFailed() {} // 对外暴露最终的数据流,供UI层观察 public LiveData<Resource<ResultType>> asLiveData() { return result; } }
关键逻辑拆解
- MediatorLiveData的作用:它能同时观察多个LiveData数据源(本地缓存+网络请求),自动处理数据源的添加/移除,完美适配“先读缓存,再决定是否请求网络”的流程。
- 线程调度:通过
AppExecutors把数据库操作放到磁盘IO线程,UI更新放到主线程,彻底避免ANR问题。 - 状态统一管理:用
Resource封装了加载中、成功、失败三种状态,UI层只需观察asLiveData()返回的数据流,就能统一处理不同状态的UI展示。
典型使用场景
这个抽象类特别适合需要离线缓存支持的APP,比如新闻、电商、社交类应用:
- 用户无网时,直接展示本地缓存内容
- 用户有网时,自动同步最新数据并更新缓存
- 所有网络请求的状态(加载、成功、失败)都能统一处理,不用每个请求都写一遍重复逻辑
内容的提问来源于stack exchange,提问作者flopshot
相关产品推荐
相关产品推荐

