我有:
API,返回JSON中的数据列表.
我的目标:
通过Retrofit RxJava获取此数据.
我的问题:
我只需要一个网络请求,如果屏幕在完成之前旋转,我不想启动新的网络请求.此外,我需要能够从API刷新数据.
我如何解决它:
首先通过Singlton解决并使用cache()缓存Observable中的数据.
第二 – 完全重建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;
}
}
附:
同样的问题用俄语:Как правильно пересоздать закэшированный Observable используемый вместе с Retrofit?
解决方法:
最后我解决了这个问题:
我在singlton中创建BehaviorSubject.它从Obtrable接收onError或onNext,它由Retrofit创建. Fragment订阅BehaviorSubject并接收带有数据或错误的最后一个事件.当我需要刷新数据时,我重新创建BehaviorSubject,重新订阅Retrofit的Observable以在singlton中接收数据或错误并重新订阅片段中的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 one rror(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 one rror(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);
}
}