IT박스

EditText에서 텍스트가 변경된 후 0.5 초 후에 어떻게해야합니까?

itboxs 2020. 12. 6. 21:21
반응형

EditText에서 텍스트가 변경된 후 0.5 초 후에 어떻게해야합니까?


EditText를 사용하여 내 목록을 필터링하고 있습니다. 사용자가 EditText 입력을 마친 후 0.5 초 후에 목록을 필터링하고 싶습니다 . 이 목적으로 afterTextChanged이벤트를 사용했습니다 TextWatcher. 그러나이 이벤트는 EditText에서 문자가 변경 될 때마다 발생합니다.

어떻게해야합니까?


editText.addTextChangedListener(
    new TextWatcher() {
        @Override public void onTextChanged(CharSequence s, int start, int before, int count) { }
        @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

        private Timer timer=new Timer();
        private final long DELAY = 1000; // milliseconds

        @Override
        public void afterTextChanged(final Editable s) {
            timer.cancel();
            timer = new Timer();
            timer.schedule(
                new TimerTask() {
                    @Override
                    public void run() {
                        // TODO: do what you need here (refresh list)
                        // you will probably need to use runOnUiThread(Runnable action) for some specific actions
                    }
                }, 
                DELAY
            );
        }
    }
);

비결은 Timer텍스트 EditText가 변경 될 때마다 취소하고 일정을 다시 잡는 것 입니다. 행운을 빕니다!

업데이트 지연 시간 설정에 관심이있는 사람들은 이 게시물을 참조하십시오 .


postDelayed () 메서드와 함께 Handler를 더 잘 사용하십시오. Android의 구현에서 Timer는 작업을 실행할 때마다 새 스레드를 만듭니다. 그러나 Handler는 원하는 스레드에 연결할 수있는 자체 Looper를 가지고 있으므로 스레드를 생성하는 데 추가 비용을 지불하지 않습니다.

 Handler handler = new Handler(Looper.getMainLooper() /*UI thread*/);
 Runnable workRunnable;
 @Override public void afterTextChanged(Editable s) {
    handler.removeCallbacks(workRunnable);
    workRunnable = () -> doSmth(s.toString());
    handler.postDelayed(workRunnable, 500 /*delay*/);
 }

 private final void doSmth(String str) {
    //
 }

RxBindings 를 사용할 수 있으며 이는 최상의 솔루션입니다. RxJava 연산자 디 바운스에 대한 가이드를 참조하십시오. 귀하의 경우에는 이것이 훌륭 할 것이라고 확신합니다.

RxTextView.textChanges(editTextVariableName)
            .debounce(500, TimeUnit.MILLISECONDS)
            .subscribe(new Action1<String>() {
                @Override
                public void call(String value) {
                    // do some work with the updated text
                }
            });

http://reactivex.io/documentation/operators/debounce.html


위의 솔루션 중 어느 것도 나를 위해 일했습니다.

TextWatcher가 검색보기에 입력 한 모든 문자에 대해 실행하지 않고 진행 상황을 표시하는 방법이 필요했습니다. 즉, UI 스레드에 액세스해야합니다.

private final TextWatcher textWatcherSearchListener = new TextWatcher() {
    final android.os.Handler handler = new android.os.Handler();
    Runnable runnable;

    public void onTextChanged(final CharSequence s, int start, final int before, int count) {
        handler.removeCallbacks(runnable);
    }

    @Override
    public void afterTextChanged(final Editable s) {
        //show some progress, because you can access UI here
        runnable = new Runnable() {
            @Override
            public void run() {
                //do some work with s.toString()
            }
        };
        handler.postDelayed(runnable, 500);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
};

모든 onTextChanged에서 핸들러 제거 (사용자가 새 문자를 입력 할 때 호출 됨). afterTextChanged는 새 Runnable을 시작할 수있는 입력 필드 내에서 텍스트가 변경된 후 호출되지만 사용자가 더 많은 문자를 입력하면 취소됩니다 (이 콜백이 호출 될 때 자세한 정보는 this 참조 ). 사용자가 더 이상 문자를 입력하지 않으면 간격이 postDelayed로 전달되고 해당 텍스트로 수행해야하는 작업을 호출합니다.

이 코드는 모든 주요 사용자 입력이 아닌 간격 당 한 번만 실행됩니다. 미래의 누군가에게 도움이되기를 바랍니다.


그들이 글을 다 읽었는지 어떻게 알 수 있습니까? 편집 텍스트가 초점을 잃는다 고요? 그런 다음 setOnFocusChangedListener가 있습니다.

문제의 최근 편집에 응답 : 최신 키 입력 후 특정 시간을 기다리려면 첫 번째 키 누름 (TextWatcher 사용)에서 스레드를 시작해야합니다. 최신 키 입력 시간을 지속적으로 등록하십시오. 스레드가 최근 키 입력 시간 + 0.5 초까지 잠자기 상태로 둡니다. 최신 키 입력의 타임 스탬프가 업데이트되지 않은 경우 의도 한대로 수행하십시오.


당신은 또한 사용할 수 있습니다 TextWatcher의 인터페이스 및 사용자 정의 클래스를 만들 구현이 여러 번하여 다시 사용하는 것을 CustomTextWatcher을 하고 또한 당신이 의견을 전달할 수 있습니다 또는 무엇이든 당신이 생성자에해야 할 수도 있습니다 :

public abstract class CustomTextWatcher implements TextWatcher { //Notice abstract class so we leave abstract method textWasChanged() for implementing class to define it

    private final TextView myTextView; //Remember EditText is a TextView so this works for EditText also


    public AddressTextWatcher(TextView tView) { //Notice I'm passing a view at the constructor, but you can pass other variables or whatever you need
        myTextView= tView;

    }

    private Timer timer = new Timer();
    private final int DELAY = 500; //milliseconds of delay for timer

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(final Editable s) {
        timer.cancel();
        timer = new Timer();

        timer.schedule(

                new TimerTask() {
                    @Override
                    public void run() {
                        textWasChanged();
                    }
                },
                DELAY

        );
    }

    public abstract void textWasChanged(); //Notice abstract method to leave implementation to implementing class

}

이제 활동에서 다음과 같이 사용할 수 있습니다.

    myEditText.addTextChangedListener(new CustomTextWatcher(myEditText) { //Notice I'm passing in constructor of CustomTextWatcher myEditText I needed to use
        @Override
        public void textWasChanged() {
            //doSomething(); this is method inside your activity
        }
    });

Kotlin 확장 기능 및 코 루틴 사용 :

fun AppCompatEditText.afterTextChangedDebounce(delayMillis: Long, input: (String) -> Unit) {
var lastInput = ""
var debounceJob: Job? = null
val uiScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
this.addTextChangedListener(object : TextWatcher {
    override fun afterTextChanged(editable: Editable?) {
        if (editable != null) {
            val newtInput = editable.toString()
            debounceJob?.cancel()
            if (lastInput != newtInput) {
                lastInput = newtInput
                debounceJob = uiScope.launch {
                    delay(delayMillis)
                    if (lastInput == newtInput) {
                        input(newtInput)
                    }
                }
            }
        }
    }

    override fun beforeTextChanged(cs: CharSequence?, start: Int, count: Int, after: Int) {}
    override fun onTextChanged(cs: CharSequence?, start: Int, before: Int, count: Int) {}
})}

타이머를 사용할 수 있으며 텍스트를 입력 한 후 600ms 동안 대기합니다. 600ms의 지연을 사용하여 afterTextChanged () 안에 코드를 넣습니다.

@Override
    public void afterTextChanged(Editable arg0) {
        // user typed: start the timer
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                // do your actual work here
               editText.setText(et.getText().toString());

            }
        }, 600); // 600ms delay before the timer executes the „run“ method from TimerTask
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // nothing to do here
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // user is typing: reset already started timer (if existing)
        if (timer != null) {
            timer.cancel();
        }
    }
};

그것은 입력을 마치는 동안과 후에 이벤트입니다 ... textWatcher를 추가하고 onTextChanged 메소드에 다음을 추가하십시오.

if (charSequence.length() > 0){// your code }


textWatcher를 처음으로 만 건너 뛰려면 다음 코드를 추가하십시오. 이렇게하면 textWatcher가 두 번째부터 변경할 수 있습니다.

    Boolean firstchange=false;
    profileEmailEditText.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (firstchange) {
                        emailAlertText.setVisibility(View.VISIBLE);
                    }
                    else {
                        firstchange=true;
                    }
                }

                @Override
                public void afterTextChanged(Editable s) {

                }
            });

Kotlin 언어에서는 이렇게 할 수 있습니다.

tv_search.addTextChangedListener(mTextWatcher)

private val mTextWatcher: TextWatcher = object : TextWatcher {
        private var timer = Timer()
        private val DELAY: Long = 1000

        override fun afterTextChanged(s: Editable?) {
            timer.cancel();
            timer = Timer()
            timer.schedule(object : TimerTask() {
                override fun run() {
                         //DO YOUR STUFF HERE
                }
            }, 1000)
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

    }

EditorActionListener그 목적으로 사용할 수 있습니다 .

editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            //Do something here
            return true;
        }
        return false;
    }
});

귀하의 경우에 타이머를 사용하는 것은 매번 새로운 개체를 만들기 때문에 최선의 해결책이 아닙니다. Timer 문서 ( http://developer.android.com/reference/java/util/Timer.html ) 에 따르면 ScheduledThreadPoolExecutor를 사용하는 것이 좋습니다.

"Timers schedule one-shot or recurring tasks for execution. Prefer ScheduledThreadPoolExecutor for new code."

Here is better approach

Runnable runnabledelayedTask = new Runnable(){
    @Override
    public void run(){
        //TODO perform any operation here
    }
};

editText.addTextChangedListener(
    new TextWatcher() {
        @Override public void onTextChanged(CharSequence s, int start, int before, int count) { }
        @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

        private final long DELAY = 500; // milliseconds

        @Override
        public void afterTextChanged(final Editable s) {
        ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(1);
        ScheduledFuture sf = scheduledPool.schedule(callabledelayedTask, DELAY, TimeUnit.MILLISECONDS);
        //you can cancel ScheduledFuture when needed
        }
    }
);

참고URL : https://stackoverflow.com/questions/12142021/how-can-i-do-something-0-5-second-after-text-changed-in-my-edittext

반응형