我尝试获取并渲染一些数据,如下所示
原始数据类
@Data @AllArgsConstructor class Category {
String name;
List<String> items;
}
演示课
@Data @AllArgsConstructor class ViewModel {
public static final int TYPE_HEADER = 0;
public static final int TYPE_ITEM = 1;
int type;
String category;
String itemName;
}
以下代码是请求并将订阅数据转换为表示对象。
Observable.create(new Observable.OnSubscribe<Category>() {
@Override public void call(Subscriber<? super Category> subscriber) {
subscriber.onNext(new Category("1", Lists.newArrayList("", "a", "b")));
subscriber.onNext(new Category("2", Lists.newArrayList("")));// this data does not output
subscriber.onNext(new Category("3", Lists.newArrayList("c", "", "d")));
subscriber.onNext(new Category("4", Lists.newArrayList("e", "f", "")));
}
}).flatMap(new Func1<Category, Observable<ViewModel>>() {
@Override public Observable<ViewModel> call(Category category) {
// TODO make this block to one line
// 1. clean response data and transform to ViewModel
List<ViewModel> cleanedItems = Lists.newArrayList(
Observable.from(category.getItems()).filter(new Func1<String, Boolean>() {
@Override public Boolean call(String s) {
return s != null && !s.isEmpty();
}
}).map(new Func1<String, ViewModel>() {
@Override public ViewModel call(String item) {
return new ViewModel(ViewModel.TYPE_ITEM, null, item);
}
}).toBlocking().toIterable());
if (cleanedItems.isEmpty()) {
// 2. case : skip
return Observable.empty();
} else {
// 3. case : add header and cleaned data
return Observable.concat(
Observable.just(new ViewModel(ViewModel.TYPE_HEADER, category.getName(), null)),
Observable.from(cleanedItems));
}
}
}).subscribe(new Action1<ViewModel>() {
@Override public void call(ViewModel viewModel) {
// render data
System.out.println(viewModel.toString());
}
});
输出
ViewModel(type=0, category=1, itemName=null)
ViewModel(type=1, category=null, itemName=a)
ViewModel(type=1, category=null, itemName=b)
ViewModel(type=0, category=3, itemName=null)
ViewModel(type=1, category=null, itemName=c)
ViewModel(type=1, category=null, itemName=d)
ViewModel(type=0, category=4, itemName=null)
ViewModel(type=1, category=null, itemName=e)
ViewModel(type=1, category=null, itemName=f)
我尝试将1,2,3,(注释)语句写入1行(或更易读的方式),但我不知道。
在这种情况下,defaultIfEmpty
运算符似乎不会使用。
有人有任何想法吗?
答案 0 :(得分:10)
这个怎么样:
public static <T, R> Func1<? super T, ? extends Observable<? extends R>> ternary(
Func1<T, Boolean> predicate,
Func1<? super T, ? extends Observable<? extends R>> ifTrue,
Func1<? super T, ? extends Observable<? extends R>> ifFalse) {
return (item) -> predicate.call(item)
? ifTrue.call(item)
: ifFalse.call(item);
}
你可以这样使用它:
.map(CharSequence::toString)
.distinctUntilChanged()
.flatMap(ternary(Strings::notNullOrEmpty,
(kw) -> userRelationshipApi.searchFollowing(kw, null),
(kw) -> Observable.just(selectedUserListAdapter.getUsers())))
.subscribe(...)
答案 1 :(得分:0)
AFAIK你不能用一行来填充它。 您必须确定流是否为空,如果不再次发出项目。您可以使用缓存来避免重复计算。
Observable.create(new Observable.OnSubscribe<Category>() {
@Override
public void call(Subscriber<? super Category> subscriber) {
subscriber.onNext(new Category("1", Lists.newArrayList("", "a", "b")));
subscriber.onNext(new Category("2", Lists.newArrayList("")));// this data does not output
subscriber.onNext(new Category("3", Lists.newArrayList("c", "", "d")));
subscriber.onNext(new Category("4", Lists.newArrayList("e", "f", "")));
subscriber.onCompleted();
}
}).flatMap(new Func1<Category, Observable<ViewModel>>() {
@Override
public Observable<ViewModel> call(Category category) {
final Observable<ViewModel> cleanedItems = Observable.from(category.getItems()).filter(new Func1<String, Boolean>() {
@Override
public Boolean call(String s) {
return s != null && !s.isEmpty();
}
}).map(new Func1<String, ViewModel>() {
@Override
public ViewModel call(String item) {
return new ViewModel(ViewModel.TYPE_ITEM, null, item);
}
}).cache();
return cleanedItems.isEmpty().flatMap(new Func1<Boolean, Observable<ViewModel>>() {
@Override
public Observable<ViewModel> call(Boolean aBoolean) {
if (aBoolean) {
return Observable.empty();
} else {
return Observable.concat(
Observable.just(new ViewModel(ViewModel.TYPE_HEADER, category.getName(), null)),
cleanedItems);
}
}
});
}
}).subscribe(new Action1<ViewModel>() {
@Override
public void call(ViewModel viewModel) {
// render data
System.out.println(viewModel.toString());
}
});
但是,有时您可以使用其他api来使代码更简单,而不是尽可能使用rxjava。在您的情况下,您可以使用例如stream api:
.flatMap(new Func1<Category, Observable<ViewModel>>() {
@Override
public Observable<ViewModel> call(Category category) {
List<ViewModel> items = category.getItems().stream().filter(s -> s != null && !s.isEmpty()).map(s -> new ViewModel(ViewModel.TYPE_ITEM, null, s)).collect(Collectors.toList());
if (items.isEmpty()) {
return Observable.empty();
} else {
items.add(0, new ViewModel(ViewModel.TYPE_HEADER, category.getName(), null));
return Observable.from(items);
}
}
})
答案 2 :(得分:0)
您可以将operator filter()与switchIfEmpty(...)
一起使用