- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有:
API,返回 JSON
格式的数据列表。
我的目标:
通过Retrofit
+RxJava
获取这些数据。
我的问题:
我只需要一个网络请求,如果屏幕在完成之前旋转,我不想开始新的请求。我还需要能够从 API 刷新数据。
我是如何解决的:
首先是通过 Singlton 解决的,并使用 cache()
在 Observable
中缓存数据。
第二 - 完全重新创建 Retrofit
对象 (1)、retrofit-interface 的实例 (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
。它从 Observable
接收 onError
或 onNext
,Retrofit
创建。 Fragment 订阅 BehaviorSubject
并接收其最后一个带有数据或错误的事件。当我需要刷新数据时,我重新创建BehaviorSubject
,重新订阅Retrofit
的Observable
来接收数据或单例中的错误并重新在 fragment 中订阅 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;
}
}
fragment :
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);
}
}
关于java - 如何重新创建或重置缓存的 Observable,与 Retrofit 一起使用以获取新数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38173653/
我有一个“设置首选项”屏幕。它有一个 ListPreference 和一个 CheckBoxPreference。当我选择 ListPreference 的一项时,我想更改应用程序的日期格式。另外,通
我试图找到创 build 置/配置窗口的示例。单击菜单项中的“选项”操作可启动设置窗口。我想弄清楚如何从主窗口打开第二个窗口。以及新窗口如何将设置信息返回主窗口。尝试使用 QDialog 或一些继承的
我在 Lnux 上有 Qt 应用程序。我想为此创建一个可执行文件/设置以便在 Windows 上分发它并且不需要安装 Qt。我通过包含所有 dll 为此创建了可执行文件但要运行它,用户需要进入文件夹。
我正在尝试创建一个有点动态的 html 类,它根据类末尾包含的数字设置宽度 %。注意:类名将始终以“gallery-item-”开头 示例:div.gallery-item-20 = 20% 宽度 我
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 6 年前。 Improve this qu
在我的应用程序中,我想记住一些变量,例如,如果用户登录过一次,那么他们将在下次重新打开应用程序时登录,或者如果他们决定禁用某些提醒,应用程序可以检查该变量是否是错误的,将不再显示该提醒。理想情况下,这
我在 Netbeans 中开发了一个应用程序,它连接到远程计算机的消息队列并发送消息。该应用程序还有其他功能。项目完成后,我清理并构建应用程序,然后 Netbeans 创建一个 jar 文件。 但我的
我创建了一个 Outlook 加载项,需要创建一个设置以使其可分发(我是新手,所以请原谅新手评论) Outlook -2010 Vs -2010 .Net 4.0 我读了一些地方,最简单的方法就是发
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: How to make installer pack of Java swing Application Proje
这个问题肯定已经被很多人解决过很多次了,但是经过几个小时的研究,我仍然没有找到我要找的东西。 我有一个 ExportSettings.settings 文件,其中包含一堆设置( bool 值、字符串、
我想为我的项目创建一个安装程序,以便它可以安装在任何电脑上而无需安装头文件。我怎样才能做到这一点? 最佳答案 一般有两种分发程序的方法: 源代码分发(要构建的源代码)。最常见的方法是使用 GNU au
如何在这样的动态壁纸中创 build 置 Activity ? Example Picture 我只用一个简单的文本构建了设置 Activity ,但遇到了一些问题。第一个问题是我不能为此 Activ
我用 GUI 创建了一个简单的软件。它有几个源文件。我可以在我的编辑器中运行该项目。我认为它已经为 1.0 版本做好了准备。但我不知道如何为我的软件创 build 置/安装程序。 源代码是python
我的 SettingsActivity当前扩展了 Android Studio 生成的类,AppCompatPreferenceActivity扩展 PreferenceActivity . Acti
我正在使用 .NET 为 IE 开发工具栏。目前,我使用 gacutil 插入我的 .NET 程序集,并使用 regasm 注册我的 COM 程序集。 我想为项目创建一个设置 (MSI),但我似乎无法
在为设置页面创建 Activity 后,我注意到 if (mCurrentValue !== value) 中的 mCurrentValue !== value 返回警告: Identity equa
我在 Visual Studio 10 中创建了一个项目,该项目使用 Mysql 数据库和 Crystalreports 以及 它。但是我不知道如何进行自动安装 Mysql 和 Crystalrepo
我正在尝试在我的 C# 项目中使用 Sqlite 数据库,并且我在 IDE 中做得很好。我的问题是当我为我的项目制作安装包并安装它时,程序无法访问 sqlite 数据库。我也知道这是因为用户没有访问文
我有一个大型 Web 应用程序(带有 11 子系统的 ErP),我想使用 Microsoft WebPI 为它创建一个设置。 目前,我们每周向客户发送一次应用程序(用于每周更新)。 我们在此应用程序中
所以我对工资单申请的最终查询是 - 如何为薪资申请创 build 置? 我需要知道的一切- 如何将设置项目添加到我现有的解决方案 如何将解决方案中的文件添加到安装项目中,以及添加哪些文件添加和在什么文
我是一名优秀的程序员,十分优秀!