'SearchView not calls onQueryTextChange on second dot

My Activity has SearchView, which should have filtered query. I am filtering it via onQueryTextListener. Idea is that disable typing not allowed chars, like dot, comma, slash and etc - only [A-Z] is allowed Here is code (I am using Kotlin, but it is readable for Java):

var shouldQueryChangeBeInvoked = true

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    searchField.setOnQueryTextListener(this)
}

override fun setSearchQuery(query: String) {
    shouldQueryChangeBeInvoked = false
    searchField.setQuery(query, false)
    shouldQueryChangeBeInvoked = true
}

override fun onQueryTextChange(newText: String?): Boolean {
    if (!shouldQueryChangeBeInvoked) {
        return false
    }
    val validQuery = validateQuery(newText)
    validQuery?.let { setSearchQuery(it) }
    return false
}

When I type, for example, "ABC." it converts to "ABC". So, it works fine. But when I type dot(".") second time onQueryTextChange doesn't invokes at all - I have set breakpoint on first line of the method. It was tested on two different phones, so it is not keyboard settings or smth like that. Why listener doesn't invoke?

EDIT

Validation of query I making with Regex like that:

fun validateQuery(query: String?): String? {
    val regex = Regex("^([A-Z]+)")
    // Return first match or null
    return query?.let { regex.find(it.toUpperCase()) }?.value
}

Don't care about Regex creation - I provide it via DI, so, it creates only once per activity. Maybe it can be problem?



Solution 1:[1]

Thanks a lot to @pskink!

I have implemented custom SearchView with filter input query and ability to disable triggering onQueryTextChange on setQuery. It is Kotlin, let's move on to that beautiful language :) I hope it will be useful for someone.

Here is Code on Gist

Solution 2:[2]

I have found problem: it is bad to change query text inside of onQueryTextChange - if we look inside of SearchView class, there is such code:

void onTextChanged(CharSequence newText) {
    ...
    if (mOnQueryChangeListener != null && !TextUtils.equals(newText, mOldQueryText)) {
        mOnQueryChangeListener.onQueryTextChange(newText.toString());
    }
    mOldQueryText = newText.toString();
}

So, old query text will be updated two times - first time with correct query "ABC", and second time with wrong one "ABC..", as I understand well.

I will ask other question separately about changing query after onQueryTextChange

Solution 3:[3]

you can use coroutine

override fun onQueryTextChange(newText: String?): Boolean {
        if (!newText.isNullOrEmpty()) {
            val searchText = "[^A-Za-z0-9-]+".toRegex().replace(newText, "")
            if (searchText != newText) {
                CoroutineScope(Dispatchers.Main).launch {
                    binding.createPostTopicChooserSearch.setQuery(searchText, false)
                }
                return true
            }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DefaultXYZ
Solution 2 DefaultXYZ
Solution 3 david55