如何阻止现有的异步网络请求?
How to block existing async web requests?
我已经向第三方库提供了回调,该库在不同时间调用提供的方法,为我提供已更改的对象。然后我执行异步 Web 请求以获取更多详细信息并将它们设置在该对象上,下面是一个类似的示例;
public void update(Person person) {
if (person.getId() == -1) {
mService.getPersonDetails()
.flatMap(..)
.skip(..)
.subscribe(personResult -> person.setId(personResult.getId()))
}
}
更新被调用了很多次,应该只在对象没有 ID 时执行查询。问题是至少有两个请求被发送,因为第一个查询尚未完成。
如何同步此方法调用,以便为通过回调传递的每个对象只发送一个请求?我只想阻止对该确切对象的请求,因此如果 update() 提供不同的对象,则可以发送新请求。
好吧,你可以简单地 synchronize
它。
public synchronized void update(Person person)
您可以使用 distinct
operator. Here's a general idea of how you could do that using a PublishSubject
(JavaDoc 过滤您的 observable 的输入)(注意这是凭记忆写的,我还没有测试过):
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);
}
当然,您必须在 Person
class 上实现 equals
方法(正如 Marek 指出的那样,这将导致传入的所有对象被缓存在内存中)或实现 distinct(Func)
变体。
该方法采用 'key selector' 函数来区分对象。如果您的对象相当重并且您担心内存(例如,如果您在 Android 上),这可能是更好的方法。像这样:
.distinct(new Func1<Person, Integer>() {
@Override
public Integer call(Person person) {
return person.hashCode();
}
})
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()))
}
}
}
我已经向第三方库提供了回调,该库在不同时间调用提供的方法,为我提供已更改的对象。然后我执行异步 Web 请求以获取更多详细信息并将它们设置在该对象上,下面是一个类似的示例;
public void update(Person person) {
if (person.getId() == -1) {
mService.getPersonDetails()
.flatMap(..)
.skip(..)
.subscribe(personResult -> person.setId(personResult.getId()))
}
}
更新被调用了很多次,应该只在对象没有 ID 时执行查询。问题是至少有两个请求被发送,因为第一个查询尚未完成。
如何同步此方法调用,以便为通过回调传递的每个对象只发送一个请求?我只想阻止对该确切对象的请求,因此如果 update() 提供不同的对象,则可以发送新请求。
好吧,你可以简单地 synchronize
它。
public synchronized void update(Person person)
您可以使用 distinct
operator. Here's a general idea of how you could do that using a PublishSubject
(JavaDoc 过滤您的 observable 的输入)(注意这是凭记忆写的,我还没有测试过):
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);
}
当然,您必须在 Person
class 上实现 equals
方法(正如 Marek 指出的那样,这将导致传入的所有对象被缓存在内存中)或实现 distinct(Func)
变体。
该方法采用 'key selector' 函数来区分对象。如果您的对象相当重并且您担心内存(例如,如果您在 Android 上),这可能是更好的方法。像这样:
.distinct(new Func1<Person, Integer>() {
@Override
public Integer call(Person person) {
return person.hashCode();
}
})
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()))
}
}
}