我是RxJava的新手,所以我深深的道歉,如果这个主题已经被覆盖或对你们中的某些人来说似乎很容易。我一直在寻找一个没有运气的解决方案。
我的许多API调用都基于原始的Google LiveData NetworkBoundResource类。由于业务逻辑的复杂性,我决定从LiveData迁移到RxJava。我将Kotlin版本https://android.jlelse.eu/networkboundresource-with-rxjava-and-kotlin-sealed-classes-1574bc516f82转换为Java版本并相应地调整了其余的实现。
public abstract class NetworkBoundResource<ResultType, RequestType> {
private final String TAG = NetworkBoundResource.class.getSimpleName();
private Flowable<Resource<ResultType>> result;
protected NetworkBoundResource() {
// Lazy db observable.
Flowable<ResultType> dbObservable = Flowable.defer(() ->
loadFromDb()
// Read from disk on Computation Scheduler
.subscribeOn(Schedulers.computation())
);
// Lazy network observable.
Flowable<ResultType> networkObservable = Flowable.defer(() ->
createCall()
// Request API on IO Scheduler
.subscribeOn(Schedulers.io())
// Read/Write to disk on Computation Scheduler
.observeOn(Schedulers.computation())
.doOnNext (request -> {
if (request.isSuccessful()) {
saveCallResult(processResponse(request));
} else {
processInternalError(request);
}
})
.onErrorReturn (throwable -> {
throw Exceptions.propagate(throwable);
})
.flatMap(__ -> loadFromDb())
);
result = NetworkUtils.isNetworkStatusAvailable()
? networkObservable
.map(Resource::success)
.onErrorReturn (t -> Resource.error(t.getMessage(), null))
.observeOn(AndroidSchedulers.mainThread())
.startWith(Resource::loading)
: dbObservable
.map(Resource::success)
.onErrorReturn (t -> Resource.error(t.getMessage(), null))
.observeOn(AndroidSchedulers.mainThread())
.startWith(Resource::loading);
}
public Flowable<Resource<ResultType>> asFlowable() {
return result;
}
private RequestType processResponse(Response<RequestType> response) {
return response.body();
}
private void processInternalError(Response<RequestType> response){
String error = null;
if (response.errorBody() != null) {
try {
error = response.errorBody().string();
} catch (java.io.IOException ignored) {
android.util.Log.e(TAG, "Error while parsing response: " + ignored.getMessage());
}
throw Exceptions.propagate(new Throwable(response.code() + ": " + error));
}
}
protected abstract void saveCallResult(@NonNull RequestType item);
protected abstract Flowable<ResultType> loadFromDb();
protected abstract Flowable<Response<RequestType>> createCall();
}
订阅Steam的My View模型
public abstract class ItemListViewModel<T extends IListItem> extends AndroidViewModel {
private MutableLiveData<Resource<List<T>>> itemListObservable;
private Disposable disposable;
protected ItemListViewModel(Application application) {
super(application);
itemListObservable = new MutableLiveData<>();
subscribe();
}
public LiveData<Resource<List<T>>> getItemListObservable() {
return itemListObservable;
}
private void subscribe() {
disposable = loadListItem()
.subscribe(
list -> itemListObservable.setValue(list),
(Throwable t) -> itemListObservable.setValue(Resource.error(t.getMessage(), null))
);
DisposableManager.add(disposable);
}
@Override
protected void onCleared() {
disposable.dispose();
}
protected abstract void init();
protected abstract Flowable<Resource<List<T>>> loadListItem();
}
我的通用片段正在处理资源状态
public abstract class ListItemFragment<T extends IListItem> extends Fragment {
protected ItemListAdapter<T> adapter;
protected RecyclerViewBinding binding;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = DataBindingUtil.inflate(inflater, R.layout.recycler_view, container, false);
binding.recyclerView.setAdapter(adapter);
binding.recyclerView.setHasFixedSize(true);
binding.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
binding.setIsLoading(true);
return binding.getRoot();
}
protected void observeViewModel(ItemListViewModel<T> viewModel) {
// Observe and update the list when the data changes
viewModel.getItemListObservable().observe(this, (@Nullable Resource<List<T>> iObservables) -> {
if (iObservables != null) {
processResponse(iObservables);
}
});
}
private void processResponse(Resource<List<T>> resource) {
switch (resource.status) {
case LOADING:
renderLoadingState();
break;
case SUCCESS:
renderDataState(resource.data);
break;
case ERROR:
renderErrorState(resource.message);
break;
}
}
private void renderLoadingState(){
binding.setIsLoading(true);
adapter.replace(Collections.emptyList());
}
private void renderDataState(List<T> data){
binding.setIsLoading(false);
adapter.replace(data);
}
private void renderErrorState(String error){
Toast.makeText(this.getContext(),error, Toast.LENGTH_SHORT).show();
}
}
虽然我按照说明订阅了createCall(),但它永远不会被触发。在我的日志拦截器中看不到它像之前那样
我的猜测是Flowable&gt; Retrofit没有正确识别。我确保将squareplapo中的CallAdapterFactory添加到我的HttpClient
BDRepository(String URL) {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.enableComplexMapKeySerialization();
Gson gson = gsonBuilder.create();
retrofit = new Retrofit
.Builder()
.baseUrl(URL)
.client(CustomTrust.getHttpClient())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
我的gradle conf
//API request
implementation "com.squareup.retrofit2:retrofit:$rootProject.retrofit"
implementation "com.squareup.retrofit2:converter-gson:$rootProject.retrofit"
implementation "com.squareup.retrofit2:adapter-rxjava2:$rootProject.retrofit"
API调用在浏览器中尝试时返回数据。 在分解代码时,我的网络始终可用,因此networkObservable应该是实际的流。
我的改装服务
@GET("items")
Flowable<Response<List<Items>>> getItemList(@Query("lang") String
language);
非常感谢任何帮助