2016-08-11 42 views
3

我正在处理一个项目,该项目需要我根据用户输入的查询通过名称过长的联系人列表。当我仍在过滤列表时,用户可以输入和删除字符。例如,我可能有一个包含5000个联系人的列表:在Java中对列表进行增量过滤

FirstName1 LastName1 
FirstName2 LastName2 
... 
FirstName5000 LastName5000 

用户有一种形式,他/她可以输入搜索条件,清单应缩小到只显示那些符合搜索条件的联系人。这里是我有问题,如果用户输入说

J 

我应该过滤列表,只显示其名字或姓氏以“J”的联系人。但是,用户可能会输入另一个字符或删除字符,在这种情况下,我需要重新开始对列表进行过滤。我的问题当然是我想以一种有效的方式做到这一点,而不是等到用字母'J'完成过滤之后才开始用新标准过滤。任何想法/建议?

+0

什么是您的用户界面(手机或网络)? –

+0

你基本上可以使用任务来更新已经过滤的结果的队列,然后根据这些进行细化(而你的“主要搜索者”只根据最新的查询在队列中放置新的队列) – Rogue

+0

@ShlomiHaver它是移动的。 Android –

回答

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为下一:

// 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); 

代码取消以前计划任务:

创建的ScheduledExecutorService和安排任务代码(要启动的用户修改任何时候的东西)

// 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); 

注:这些代码片段只是为了显示想法,他们不是我蚂蚁是完美的

+0

由于两种方法都等待1秒(对于UI而言很大)并且不会停止当前正在执行的任务。第二种方法中的巨大问题,因为您将执行程序声明为单一线程:以下查询将等待先前的 – JohnnyAW

+0

@JohnnyAW thx给出反对票的原因。 1.这些代码片段仅仅是为了展示这个想法,只有OP可以决定什么是最好的形式,所以1秒只是一个随机值,我可以放400毫秒或任何你想要的,答案的主要思想仍然是一样的。 2.我取消任务是你可以做的最好的任务,因为你不能停止一项任务,你只能检查它是否在执行任务时被中断,如果是的话则中断任务。 3.因为我们只有一个字段,所以我们只需要一个线程,因为我们显然不想在parralel中执行多个查询。 –

+0

1:为什么您甚至使用延迟?高于100-200毫秒的所有信息都会导致用户遇到输入延迟。 2:你为什么没有展示如何检查任务是否被取消? 3:我认为你没有在第二种方法中遇到大问题:如果你不检查取消,你的下面的查询将等待第一个查询来完成搜索,这正是OP想要避免的!你不需要2个线程,但你必须检查取消 – JohnnyAW

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线程上调用以避免设置问题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; 
相关问题