我正在开展一个项目,要求我根据用户输入的查询按名称过滤一长串联系人。当我仍在过滤列表时,用户可以输入和删除字符。例如,我可能有一个包含5000个联系人的列表:
FirstName1 LastName1
FirstName2 LastName2
...
FirstName5000 LastName5000
用户有一个表单,他/她可以输入搜索条件,列表应缩小以仅显示符合搜索条件的联系人。如果用户输入了
,我遇到了问题J
我应该过滤列表,只显示名字或姓氏以' J'开头的联系人。但是,用户可能会输入另一个字符或删除字符,在这种情况下,我需要重新启动列表的过滤。我的问题当然是我希望以一种有效的方式做到这一点,而不是等到过滤完成后用字母' J'在我开始使用新标准过滤之前。有什么想法/建议吗?
答案 0 :(得分:0)
为了避免启动太多有助于提高可伸缩性的查询,我建议实现一种在启动查询之前等待一段时间的机制。只要用户在此时间段内修改字段内容,它就会中止上一个查询并安排新查询。
类似的东西:
创建计时器并安排任务的代码:
Timer timer = new Timer();
// Schedule my task to be executed in 200 milliseconds
timer.schedule(new TimerTask() {
@Override
public void run() {
// Launch my query here
}
}, 200L);
取消之前计划任务的代码:(在用户修改某些内容时启动)
// Cancel the previous timer which will also abort the scheduled task
timer.cancel();
// Create a new timer
timer = new Timer();
// Re-schedule the task
timer.schedule(new TimerTask() {
@Override
public void run() {
// Launch my query here
}
}, 200L);
也可以使用ScheduledExecutorService
作为下一个:
创建ScheduledExecutorService
并安排任务的代码:
// Create the ScheduledExecutorService
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
// Submit the task to be executed in 200 milliseconds
ScheduledFuture<?> future = executor.schedule(new Runnable() {
@Override
public void run() {
// Launch my query here
}
}, 200, TimeUnit.MILLISECONDS);
取消之前计划任务的代码:(在用户修改某些内容时启动)
// Cancel the task which will interrupt the thread that was executing the
// task if any
future.cancel(true);
// Re-submit the task
future = executor.schedule(new Callable<Void>() {
@Override
public Void call() throws InterruptedException {
...
// Check regularly in your code if the thread has been
// interrupted and if so throws an exception to stop
// the task immediately
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException("Thread interrupted");
}
...
}
}, 200, TimeUnit.MILLISECONDS);
NB:这些代码段只是为了表明这个想法,它们并不是完美的
答案 1 :(得分:0)
class CancelableTask implements Callable<Void> {
//need this to know, if the task was canceled
private Future<Void> myFuture;
public void setMyFuture(Future<Void> myFuture) {
this.myFuture = myFuture;
}
@Override
public Void call() throws Exception {
//we run a loop until the query is finished or task was canceled
while (!this.myFuture.isCancelled() && !myQuery.isFinished()) {
//the step should be small enough to fast detect task cancellation but big enough to avoid too much overhead
myQuery.performQueryStep();
}
if(!this.myFuture.isCancelled()){
//query is finished and task wasn't canceled, so we should update UI now
updateUIOnUIThread(myQuery.result());
}
return null;
}
}
现在您需要在活动中的某处创建ExecutorService
:
//1 Thread should be enough, you could use 2 Threads if your query-step is quite long and you want to start the following query faster
private ExecutorService executor = Executors.newSingleThreadExecutor();
现在我们可以使用executor
来运行任务。一旦用户更改输入,就应该调用此代码。应该在UI-Thread上调用它以避免设置currentTaskFuture
:
//check if need to cancel the currentTask
if(currentTaskFuture != null && !currentTaskFuture.isDone()){
currentTaskFuture.cancel(false);
}
CancelableTask task = new CancelableTask();
//submit the task
Future<Void> future = executor.submit(task);
task.setMyFuture(future);
//set current task's future so we can cancel it if needed
currentTaskFuture = future;