Android/RxJava,防止同类多个订阅
Android/RxJava, prevent multiple subscriptions of the same kind
早上好,我最近忙于研究 RxJava,遇到了一个问题。
我在 ViewPager 中有一个 Fragment,它在 onViewCreated() 上启动一个 HTTP 请求(由 Retrofit 和 RxJava 处理)以检索字符串列表。
它的方法是 创建订阅 并将其添加到 CompositeSubscription 对象
这是代码
final Subscription subscription = MyManager.getService().getListStringsFromWeb()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>() {
@Override
public void onCompleted() {
// DO NOTHING
}
@Override
public void onError(Throwable e) {
// DO SOMETHING
}
@Override
public void onNext(List<String> result) {
returnResultToView(result);
}
});
addSubscription(subscription);
在 onViewCreated() 的片段中,我检查是否有结果,如果没有我们调用上面的方法,如果有我们很高兴。
问题 是当我旋转设备时 "first" 订阅尚未 return,因此片段不记得数据并且它会启动另一个搜索,如果我继续轮换,我会继续添加订阅
我想知道是否有办法保留第一个订阅,当它的结果到达时,只需将它返回给片段并忽略所有其他订阅
逐步实现所需的行为:
- 启动片段和请求
- 屏幕显示正在加载图像和背景 subscription/request 已启动
- 由于第一个请求仍处于待处理状态,多次屏幕旋转保持加载图像
- 一旦第一次调用的结果返回return它到片段,因此隐藏加载图像并显示结果
非常感谢
关于 Fragments 和 RxJava 的不幸的事情是你必须以某种方式保持 observable。一种方法是让它们在 Fragment
中静态化,这样你只创建一次,然后在 onStart()
/onStop()
中创建它们 subscribe/unsubscribe 或者你决定。
如果您不喜欢制作静态变量,另一种方法是使用处理数据的保留片段。然后,数据的视图 Fragment
可以 "bind" 本身到数据片段。这种方法的优点是数据很容易被Activity的所有组件使用,它从视图中抽象出数据以便于测试,并且比生命周期组件长。
因此,对于保留的片段,您可以这样做:
public class DataFragment extends Fragment {
private Observable<List<String> stringObs;
@Override
public void onAttach(Context ctx) {
super.onAttach(ctx);
setRetainInstance(true);
}
@Override
public void onCreateView(LayoutInflater inflater, ViewGroup group, Bundle savedInsatnceState) {
return null; // no view, no problem.
}
public Observable<List<String>> getStrings() {
if (stringsObs == null) {
stringsObs = MyManager.getService()
.getListStringsFromWeb()
.cache()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
return stringsObs;
}
}
像这样将 DataFragment
添加到 FragmentManager 中:
FragmentManager fm = getFragmentManager();
DataFragment df = fm.findFragmentByTag("DataFragment");
if (df == null) {
// Only add the retained fragment if it doesn't exist. Otherwise, use the old one.
fm.beginTransaction()
.add(new DataFragment(), "DataFragment")
.commit();
}
然后在 ViewFragment 上你可以像这样订阅它:
public class ViewFragment extends Fragment {
private Subscription s;
@Override
public void onStart() {
super.onStart();
DataFragment dataFragment = (DataFragment) getFragmentManager().findFragmentByTag("DataFragment");
s = dataFragment.getStrings()
.subscribe(new Observer<List<String>() {
// Do things
});
}
@Override
public void onStop() {
super.onStop();
s.unsubscribe();
}
}
现在,您的 ViewFragment 可以随心所欲地消失和重新出现,而不会妨碍下载。以您需要的方式操作 Observables 也更容易。
早上好,我最近忙于研究 RxJava,遇到了一个问题。
我在 ViewPager 中有一个 Fragment,它在 onViewCreated() 上启动一个 HTTP 请求(由 Retrofit 和 RxJava 处理)以检索字符串列表。 它的方法是 创建订阅 并将其添加到 CompositeSubscription 对象
这是代码
final Subscription subscription = MyManager.getService().getListStringsFromWeb()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>() {
@Override
public void onCompleted() {
// DO NOTHING
}
@Override
public void onError(Throwable e) {
// DO SOMETHING
}
@Override
public void onNext(List<String> result) {
returnResultToView(result);
}
});
addSubscription(subscription);
在 onViewCreated() 的片段中,我检查是否有结果,如果没有我们调用上面的方法,如果有我们很高兴。
问题 是当我旋转设备时 "first" 订阅尚未 return,因此片段不记得数据并且它会启动另一个搜索,如果我继续轮换,我会继续添加订阅
我想知道是否有办法保留第一个订阅,当它的结果到达时,只需将它返回给片段并忽略所有其他订阅
逐步实现所需的行为:
- 启动片段和请求
- 屏幕显示正在加载图像和背景 subscription/request 已启动
- 由于第一个请求仍处于待处理状态,多次屏幕旋转保持加载图像
- 一旦第一次调用的结果返回return它到片段,因此隐藏加载图像并显示结果
非常感谢
关于 Fragments 和 RxJava 的不幸的事情是你必须以某种方式保持 observable。一种方法是让它们在 Fragment
中静态化,这样你只创建一次,然后在 onStart()
/onStop()
中创建它们 subscribe/unsubscribe 或者你决定。
如果您不喜欢制作静态变量,另一种方法是使用处理数据的保留片段。然后,数据的视图 Fragment
可以 "bind" 本身到数据片段。这种方法的优点是数据很容易被Activity的所有组件使用,它从视图中抽象出数据以便于测试,并且比生命周期组件长。
因此,对于保留的片段,您可以这样做:
public class DataFragment extends Fragment {
private Observable<List<String> stringObs;
@Override
public void onAttach(Context ctx) {
super.onAttach(ctx);
setRetainInstance(true);
}
@Override
public void onCreateView(LayoutInflater inflater, ViewGroup group, Bundle savedInsatnceState) {
return null; // no view, no problem.
}
public Observable<List<String>> getStrings() {
if (stringsObs == null) {
stringsObs = MyManager.getService()
.getListStringsFromWeb()
.cache()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
return stringsObs;
}
}
像这样将 DataFragment
添加到 FragmentManager 中:
FragmentManager fm = getFragmentManager();
DataFragment df = fm.findFragmentByTag("DataFragment");
if (df == null) {
// Only add the retained fragment if it doesn't exist. Otherwise, use the old one.
fm.beginTransaction()
.add(new DataFragment(), "DataFragment")
.commit();
}
然后在 ViewFragment 上你可以像这样订阅它:
public class ViewFragment extends Fragment {
private Subscription s;
@Override
public void onStart() {
super.onStart();
DataFragment dataFragment = (DataFragment) getFragmentManager().findFragmentByTag("DataFragment");
s = dataFragment.getStrings()
.subscribe(new Observer<List<String>() {
// Do things
});
}
@Override
public void onStop() {
super.onStop();
s.unsubscribe();
}
}
现在,您的 ViewFragment 可以随心所欲地消失和重新出现,而不会妨碍下载。以您需要的方式操作 Observables 也更容易。