我有:
API,返回JSON
中的数据列表。
我的目标:
通过Retrofit
+ RxJava
获取此数据。
我的问题:
我只需要一个网络请求,如果屏幕在完成之前旋转,我不想启动新的网络请求。此外,我需要能够从API刷新数据。
我是如何解决的:
首先通过Singlton解决并使用Observable
缓存cache()
中的数据。
第二 - 完全重新创建Retrofit
对象(1),改造界面实例(2)和Observable
(3)本身。我尝试只做3但失败 - Observable
没有重置并发出旧的缓存数据。
问题:
我重建Observable
的工作方式看起来很糟糕。重新创建缓存Observable
的正确/更好的方法是什么?
有我的Singlton来获取/重新创建Observalbe
:
public class SingltonRetrofit
{
private static RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());
private static Gson gson = new GsonBuilder().create();
private static Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Const.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(rxAdapter)
.build();
private static GetModels apiService = retrofit.create(GetModels.class);
private static Observable<ArrayList<Model>> observableModelsList;
public static void reset()
{
retrofit = new Retrofit.Builder()
.baseUrl(Const.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(rxAdapter)
.build();
apiService = retrofit.create(GetModels.class);
observableModelsList = null;
}
public static Observable<ArrayList<Model>> getModelsObservable()
{
if (observableModelsList == null)
{
observableModelsList = apiService.getModelsList().cache();
}
return observableModelsList;
}
}
P.S。
俄语中的同样问题:Как правильно пересоздать закэшированный Observable используемый вместе с Retrofit?
答案 0 :(得分:2)
最后我解决了这个问题:
我在singlton中创建BehaviorSubject
。它从onError
接收onNext
或Observable
,Retrofit
由BehaviorSubject
创建。片段订阅BehaviorSubject
并收到带有数据或错误的最后一个事件。当我需要刷新数据时,我重新创建Retrofit
,重新订阅Observable
的{{1}}以接收数据或错误,并在片段中重新订阅BehaviorSubject
public class SingltonRetrofitNew
{
private static RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());
private static Gson gson = new GsonBuilder().create();
private static Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Const.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(rxAdapter)
.build();
private static GetModels apiService = retrofit.create(GetModels.class);
private static BehaviorSubject<ArrayList<Model>> observableModelsList;
private static Observable<ArrayList<Model>> observable = apiService.getModelsList();
private static Subscription subscription;
private SingltonRetrofitNew()
{
}
public static void resetObservable()
{
observableModelsList = BehaviorSubject.create();
if (subscription != null && !subscription.isUnsubscribed())
{
subscription.unsubscribe();
}
subscription = observable.subscribe(new Subscriber<ArrayList<Model>>()
{
@Override
public void onCompleted()
{
//do nothing
}
@Override
public void onError(Throwable e)
{
observableModelsList.onError(e);
}
@Override
public void onNext(ArrayList<Model> hotels)
{
observableModelsList.onNext(hotels);
}
});
}
public static Observable<ArrayList<Model>> getModelsObservable()
{
if (observableModelsList == null)
{
resetObservable();
}
return observableModelsList;
}
}
片段:
public class FragmentsList extends Fragment
{
private static final String TAG = FragmentList.class.getSimpleName();
private Subscription subscription;
private RecyclerView recyclerView;
private ArrayList<Hotel> models = new ArrayList<>();
private boolean isLoading;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.fragment, container, false);
//init views
recyclerView = (RecyclerView) v.findViewById(R.id.recycler);
if (savedInstanceState != null)
{
models = savedInstanceState.getParcelableArrayList(Const.KEY_MODELS);
isLoading = savedInstanceState.getBoolean(Const.KEY_IS_LOADING);
}
if (models.size() == 0 || isLoading)
{
getModelsList();
}
//TODO show saved data if is
return v;
}
@Override
public void onDestroy()
{
super.onDestroy();
if (subscription != null && !subscription.isUnsubscribed())
{
subscription.unsubscribe();
}
}
private void getModelsList()
{
if (subscription != null && !subscription.isUnsubscribed())
{
subscription.unsubscribe();
}
subscription = SingltonRetrofitNew.getModelsObservable().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Subscriber<ArrayList<Hotel>>()
{
@Override
public void onCompleted()
{
Log.d(TAG, "onCompleted");
}
@Override
public void onError(Throwable e)
{
Log.d(TAG, "onError", e);
Snackbar.make(recyclerView, R.string.connection_error, Snackbar.LENGTH_SHORT)
.setAction(R.string.try_again, new View.OnClickListener()
{
@Override
public void onClick(View v)
{
SingltonRetrofitNew.reset();
getModelsList();
}
})
.show();
}
@Override
public void onNext(ArrayList<Hotel> newModels)
{
models.clear();
models.addAll(newModels);
//TODO show data
}
});
}
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(Const.KEY_MODELS, models);
outState.putBoolean(Const.KEY_IS_LOADING, isLoading);
}
}