2016-08-11 43 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; 
相關問題