2016-08-11 2 views
3

私は、ユーザが入力したクエリに基づいて長い連絡先のリストを名前でフィルタリングする必要があるプロジェクトに取り組んでいます。私はまだリストをフィルタリングしている間に、ユーザは文字を入力したり削除したりすることができます。ユーザーは、彼/彼女は、検索条件を入力することができますし、リストは、検索基準を満たすだけでそれらの連絡先を表示するために縮小する必要があるフォームを持っているJavaのリストのインクリメンタルなフィルタリング

FirstName1 LastName1 
FirstName2 LastName2 
... 
FirstName5000 LastName5000 

:たとえば、私は5000人の連絡先を含むリストを持っているかもしれません。ユーザーが

J 

を言う入るとここで私が持っている問題は、私は、リストをフィルタリングし、唯一その名または姓「J」で始まる連絡先を表示する必要があります。ただし、ユーザーは別の文字を入力したり、文字を削除したりすることがあります。この場合、リストのフィルタリングを再開する必要があります。私の問題は効率的な方法でこれを行い、新しい基準でフィルタリングを開始する前に文字 'J'でフィルタリングが完了するまで待つことではないということです。任意のアイデア/推奨事項?

+0

あなたのUI(モバイルまたはウェブ)は何ですか? –

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

コード

// 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:これらのコードスニペットは、アイデアを示すためのものであり、私ではありませんアリは完全です

+0

ExecutorをSingle Threadedと宣言して以来、2番目のメソッドの大きな問題:次のクエリは、前回の – JohnnyAW

+0

@ JohnnyAW thxがダウン投票の理由を示すのを待つことになります。 1.これらのコードスニペットは、OPが何が最善のフォームなのかを決めることができるだけのアイデアを表示することだけを目的としていますので、1秒は400ミリ秒か、それでも同じであろう。 2.私はタスクをキャンセルすることはできませんが、あなたはタスクの実装で中断されている場合にチェックすることができますし、その場合はタスクを中断することができる最高です。 3.フィールドが1つしかないので、1つのスレッドしか必要ありません。なぜなら、パラレルで複数のクエリを実行したくないからです。 –

+0

1:なぜ遅延を使用するのですか? 100〜200ミリ秒を超えるものはすべて、ユーザーが入力遅れを経験する原因となります。 2:なぜタスクがキャンセルされたかをチェックする方法を示していないのですか? 3:私はあなたが2番目の方法で大きな問題を抱えていなかったと思います。取り消しをチェックしないと、次のクエリは最初のクエリが検索を完了するのを待っています。 2スレッドは必要ありませんが、取り消しを確認する必要があります。 – JohnnyAW

0

OK、基本的にバックグラウンドスレッドでクエリを実行し、ユーザーが入力を変更して新しいものを開始すると現在実行中のクエリをキャンセルする必要があります。 は、まず私たちはあなたのクエリをラップするタスククラスを、必要とする:

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を使用することができます。このコードは、ユーザーが入力を変更するとすぐに呼び出される必要があります。currentTaskFutureの設定で問題を回避するには、UIスレッドで呼び出す必要があります。

//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; 
関連する問題