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

时间:2016-07-03 19:34:10

标签: java android retrofit rx-java rx-android

我有:

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?

1 个答案:

答案 0 :(得分:2)

最后我解决了这个问题:

我在singlton中创建BehaviorSubject。它从onError接收onNextObservableRetrofitBehaviorSubject创建。片段订阅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);
    }
}