首页 > 解决方案 > AutoCompleteTextView 使用 MergeCursor 显示来自 SearchRecentSuggestionsProvider 的错误字符串

问题描述

我正在 Android 应用程序中实现自定义搜索屏幕,并设置了 AutoCompleteTextView,并将光标设置到我的 SearchRecentSuggestionsProvider 以便为 AutoCompleteTextView 显示这些建议。

当光标仅指向 SearchRecentSuggestionsProvider 时,这可以正常工作,但是我想包含一些自定义建议,因此设置了 MergeCursor 来执行此操作。

当我这样做时,我的自定义建议会正确显示,但来自 SearchRecentSuggestionsProvider 的建议会显示为“android.resource://system/17301578”。

单击建议确实会将正确的文本添加到 AutoCompleteTextView,并逐步通过 CursorToStringConverter 确认它们正在被正确转换,但由于某种原因,这些在下拉列表中显示不正确。

任何帮助都将不胜感激,因为我找不到任何遇到类似问题的人,甚至找不到许多其他人试图通过 SearchRecentSuggestionsProvider 包含自定义建议的示例。

这是向 AutoCompleteTextView 添加建议的代码:

// Get a cursor to the SearchSuggestionsProvider
val uri =
    Uri.parse("content://" + SearchSuggestionsProvider.AUTHORITY + "/" + SearchManager.SUGGEST_URI_PATH_QUERY)
val projection = arrayOf("_id", SearchManager.SUGGEST_COLUMN_QUERY)
val suggestionCursor =
    this.context?.contentResolver?.query(uri, projection, null, arrayOf(""), null)

// Set up autocomplete for special suggestions
val specialSuggestions = mutableListOf<String>()
specialSuggestions.add("Norfolk Island")
specialSuggestions.add("Pitcairn Island")

// Create a matrix cursor for the new entries, and use a merge cursor to return it with the recent searches
val matrixCursor = MatrixCursor(projection)
for ((i, suggestion) in specialSuggestions.withIndex()) {
    matrixCursor.newRow()
        .add("_id", i)
        .add(SearchManager.SUGGEST_COLUMN_QUERY, suggestion)
}

// Set up the merge cursor
val cursor = MergeCursor(arrayOf(matrixCursor, suggestionCursor))

// Set up an adapter to the cursor
val adapter = SimpleCursorAdapter(
    this.context,
    android.R.layout.simple_list_item_1,
    cursor,
    arrayOf(SearchManager.SUGGEST_COLUMN_QUERY),
    intArrayOf(android.R.id.text1),
    SearchManager.FLAG_QUERY_REFINEMENT
)

// This ensures that the row in the cursor is returned as the suggestion string
adapter.cursorToStringConverter = SimpleCursorAdapter.CursorToStringConverter { cur ->
    cur.getString(cur.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_QUERY))
}

// This adds filtering based on what the user has typed
adapter.filterQueryProvider = FilterQueryProvider { text ->
    val filterSuggestionCursor = this.context?.contentResolver?.query(
        uri,
        projection,
        null,
        arrayOf(text.toString()),
        null
    )
    val filterMatrixCursor = MatrixCursor(projection)
    for ((i, suggestion) in specialSuggestions.filter { s -> s.contains(text, true) }.withIndex()) {
        filterMatrixCursor.newRow()
            .add("_id", i)
            .add(SearchManager.SUGGEST_COLUMN_QUERY, suggestion)
    }
    MergeCursor(arrayOf(filterMatrixCursor, filterSuggestionCursor))
}

// Add the adapter to the AutoCompleteTextView
val keywordsInput = view.findViewById<AutoCompleteTextView>(R.id.search_keywords_input)
keywordsInput.setAdapter(adapter)

以下是搜索框的部分视图:

<com.google.android.material.textfield.TextInputLayout
    style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginEnd="16dp"
    android:layout_marginStart="16dp"
    android:layout_marginTop="16dp"
    android:hint="Add Search Keywords..."
    app:endIconCheckable="true"
    android:id="@+id/search_keywords"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:endIconDrawable="@android:drawable/ic_input_add"
    app:endIconMode="custom"
    app:endIconTint="@color/colorPrimaryDark"
    app:endIconContentDescription="Add Keyword">

    <androidx.appcompat.widget.AppCompatAutoCompleteTextView
        style="@style/Widget.MaterialComponents.AutoCompleteTextView.OutlinedBox.Dense"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:completionThreshold="1"
        android:maxLines="1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:id="@+id/search_keywords_input" />

</com.google.android.material.textfield.TextInputLayout>

以下是运行中的错误的屏幕截图:

显示问题的屏幕截图

标签: androidkotlin

解决方案


似乎当您将 MergeCursor 与 MatrixCursor 和 SearchRecentSuggestionsProvider 一起使用时,您需要 SearchRecentSuggestionsProvider 中的所有列,并且顺序相同。

SearchRecentSuggestionsProvider 的投影似乎是在之后应用的(我在想 MergeCursor 会将投影与我的 MatrixCursor 合并)。

为了解决这个问题,我将 MatrixCursor 构造函数更改为:

val filterMatrixCursor = MatrixCursor(filterSuggestionCursor?.columnNames)

推荐阅读