如何重新创建或重置缓存的 Observable,与 Retrofit 一起使用以获取新数据?

How to recreate or reset cached Observable, used with Retrofit to get new data?

我有:

API,即returns数据列表在JSON.

我的目标:

通过Retrofit+RxJava获取此数据。

我的问题:

我只需要一个网络请求,如果屏幕在完成之前旋转,我不想开始新的请求。我还需要能够从 API.

刷新数据

我是怎么解决的:

首先通过 Singlton 解决并在 Observable 中使用 cache() 缓存数据。

其次 - 完全重新创建 Retrofit 对象 (1)、改造接口实例 (2) 和 Observable(3) 本身。我尝试只做 3 次,但失败了 - Observable 未重置并发出旧的缓存数据。

问题:

我重新创建 Observable 的工作方式看起来很糟糕。重新创建缓存 Observable 的 proper/better 方法是什么?


有我的辛格顿get/recreate 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?

最后我是这样解决的:

我在 singlton 中创建 BehaviorSubject。它从 Retrofit 创建的 Observable 接收 onErroronNext。片段订阅 BehaviorSubject 并接收其最后一个带有数据或错误的事件。当我需要刷新数据时,我重新创建BehaviorSubject,重新订阅RetrofitObservable来接收数据或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 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);
    }
}