2016-08-11 4 views
3

사용자가 입력 한 쿼리를 기반으로 이름순으로 긴 연락처 목록을 필터링해야하는 프로젝트를 진행하고 있습니다. 사용자는 목록을 필터링하는 동안 문자를 입력하고 삭제할 수 있습니다. 예를 들어, 나는 5000 연락처를 포함하는 목록이있을 수 있습니다 :Java에서 목록의 증분 필터링

FirstName1 LastName1 
FirstName2 LastName2 
... 
FirstName5000 LastName5000 

사용자는 그/그녀가 검색 조건을 입력 할 수 있으며 목록은 검색 기준에 맞는 연락처만을 보여 축소해야 양식을 가지고있다. 사용자가

J 

내가 목록을 필터링 만 그 이름 또는 성 'J'로 시작하는 연락처를 표시해야합니다라고 입력하면 여기, 내가 가지고있는 문제입니다. 그러나 사용자가 다른 문자를 입력하거나 문자를 삭제할 수 있습니다.이 경우 목록 필터링을 다시 시작해야합니다. 내 문제는 효율적인 방법으로이 작업을 수행하고 새로운 기준으로 필터링을 시작하기 전에 'J'라는 문자로 필터링이 완료 될 때까지 기다리지 말아야한다는 것입니다. 어떤 아이디어/추천?

+0

UI (모바일 또는 웹) 란 무엇입니까? –

+0

당신은 본질적으로 이미 필터링 된 결과의 큐를 업데이트하는 태스크를 사용할 수 있습니다. 그런 다음 "기본 검색 자"가 최신 쿼리를 기반으로 대기열에 새 서버를 배치하는 동안 해당 검색 결과를 기반으로 정제하면됩니다. – Rogue

+0

@ShlomiHaver 모바일입니다. 안드로이드 –

답변

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

이전 예약 된 작업 취소

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

NB : 이러한 코드 스 니펫은 아이디어를 나타 내기위한 것일 뿐이며, 개미가 완벽해야합니다.

+0

두 가지 방법 모두 1 초 (UI의 경우 막대한)를 기다리고 현재 실행중인 작업을 중단하지 않기 때문에 다운 투표하십시오. Executor를 Single Threaded로 선언 했으므로 두 번째 방법에서 큰 문제가 발생합니다. 다음 쿼리는 아래쪽 투표의 이유를 제공하기 위해 이전 – JohnnyAW

+0

@JohnnyAW thx를 기다립니다. 1.이 코드 스 니펫은 OP가 무엇을 가장 잘 결정할 수 있는지에 대한 아이디어를 보여주기위한 것일뿐입니다. 1 초는 400 밀리 초를 넣을 수있는 임의의 값이거나 대답의 기본 아이디어입니다. 여전히 동일 할 것이다. 2. 작업을 취소 할 수 없으면 작업을 취소 할 수 있습니다. 작업의 구현에서 중단되었는지 확인하고 작업이 중단 된 경우에만 작업을 중단 할 수 있습니다. 3. 하나의 필드가 있으므로 하나의 스레드 만 필요합니다. 하나의 스레드가 필요합니다. 두 개의 쿼리를 병렬로 –

+0

1 번 실행하고 싶지는 않습니다. 왜 지연을 사용합니까? 100-200 ms 이상의 모든 것은 사용자가 입력 지연을 경험하게합니다. 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를 사용할 수 있습니다. 이 코드는 사용자가 입력을 변경하자 마자 호출되어야합니다. 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; 
관련 문제