我已经向第三方库提供了回调,该库在不同时间调用提供的方法,为我提供了一个已更改的对象。然后我执行异步Web请求以获取更多详细信息并将其设置在该对象上,下面是一个类似的示例;
public void update(Person person) {
if (person.getId() == -1) {
mService.getPersonDetails()
.flatMap(..)
.skip(..)
.subscribe(personResult -> person.setId(personResult.getId()))
}
}
更新被调用了很多次,并且只应在对象没有ID时才执行查询。问题是,当第一个查询尚未完成时,至少会发送两个请求。
如何同步此方法调用,以便只为通过回调传递的每个Object发送一个请求?我只想阻止对该确切Object的请求,因此如果update()提供不同的对象,则可以发送新的请求。
答案 0 :(得分:3)
Adam S提供的解决方案看起来不错,但很快或以后都会导致OOM问题。这是由于不同的运营商必须存储所有唯一值。
我想到的另一个选择是使用ConcurrentMap来存储已处理的人员,并使用doOnTerminate来清理它。
private Map<Person, Boolean> map = new ConcurrentHashMap<>();
public void update(final Person person) {
if (person.getId() == -1) {
if(map.putIfAbsent(person, true)==null){
mService.getPersonDetails()
.flatMap(..)
.skip(..)
.doOnTerminate(()->map.remove(person))
.subscribe(personResult -> person.setId(personResult.getId()))
}
}
}
答案 1 :(得分:1)
您可以使用distinct
运算符过滤您的observable的输入。以下是关于如何使用PublishSubject
(JavaDoc)来做到这一点的一般概念(注意这是从记忆中写的,我还没有对此进行过测试):
private PublishSubject<Person> personSubject;
public void update(Person person) {
if (personSubject == null) {
personSubject = new PublishSubject();
personSubject
.filter(person -> person.getId() == -1)
.distinct()
.flatMap(person -> mService.getPersonDetails())
.skip(..)
.subscribe(personResult -> person.setId(personResult.getId()));
}
personSubject.onNext(person);
}
当然,您必须在equals
类上实现Person
方法(正如Marek指出的那样,将导致所有传入的对象被缓存在内存中)或实现distinct(Func)
变体。
该方法需要一个键选择器&#39;用于区分对象的函数。如果你的对象相当沉重并且你关注内存(例如,如果你在Android上),这可能是一条更好的道路。像这样:
.distinct(new Func1<Person, Integer>() {
@Override
public Integer call(Person person) {
return person.hashCode();
}
})
答案 2 :(得分:-1)
嗯,你可以简单地synchronize
。
public synchronized void update(Person person)