맞춤 검색 추천 추가

Compose 방식으로 시도
Jetpack Compose는 Android에 권장되는 UI 도구 키트입니다. Compose에서 검색 기능을 추가하는 방법을 알아봅니다.

Android 검색 대화상자 또는 검색 위젯에서 최근 검색어를 기반으로 추천 검색어를 제공할 수 있습니다. 예를 들어 사용자가 '강아지'를 검색하면 동일한 쿼리를 다시 입력할 때 이 쿼리가 추천 검색어로 표시됩니다. 그림 1은 최근 추천 검색어가 표시된 검색 대화상자의 예를 보여줍니다.

시작하기 전에 애플리케이션에서 기본 검색을 위한 검색 대화상자나 검색 위젯을 구현하세요. 방법을 알아보려면 검색 인터페이스 만들기를 참고하세요.

기본 사항

그림 1. 최근 추천 검색어가 표시된 검색 대화상자 스크린샷

최근 추천 검색어는 저장된 검색어입니다. 사용자가 추천 검색어를 선택하면 검색 활동은 이 추천 검색어가 있는 ACTION_SEARCH 인텐트를 기존에 처리하고 있는 검색어로 수신합니다.

최근 추천 검색어를 제공하려면 다음을 따라야 합니다.

  • 검색 가능 활동을 구현합니다.
  • SearchRecentSuggestionsProvider를 확장하는 콘텐츠 제공자를 만들어 애플리케이션 manifest에서 선언합니다.
  • 추천 검색어를 제공하는 콘텐츠 제공자에 관한 정보로 검색 가능한 구성을 수정합니다.
  • 검색이 실행될 때마다 콘텐츠 제공자에 쿼리를 저장합니다.

Android 시스템은 검색 대화상자를 표시하는 것처럼 대화상자 또는 검색 위젯 아래에 추천 검색어를 표시합니다. 시스템에서 추천을 가져오는 소스를 제공합니다.

시스템에서 활동이 검색 활동임을 식별하고 추천 검색어를 제공하면 사용자가 쿼리를 입력할 때 다음이 발생합니다.

  1. 시스템이 검색어 텍스트(사용자가 입력하기 시작한 모든 텍스트)를 가져와서 추천 검색어가 포함된 콘텐츠 제공자에 쿼리를 실행합니다.
  2. 콘텐츠 제공자가 검색어 텍스트와 일치하는 모든 추천 검색어를 가리키는 Cursor를 반환합니다.
  3. 시스템에 Cursor가 제공한 추천 목록이 표시됩니다.

최근 추천 검색어가 표시되면 다음과 같은 결과가 발생할 수 있습니다.

  • 사용자가 다른 키를 입력하거나 임의의 방식으로 쿼리를 변경하면 위의 단계가 반복되고 추천 검색어 목록이 업데이트됩니다.
  • 사용자가 검색을 실행하면 추천 검색어가 무시되고 검색이 일반 ACTION_SEARCH 인텐트를 사용하여 검색 활동에 전달됩니다.
  • 사용자가 추천 검색어를 선택하면 추천된 텍스트를 쿼리로 사용하여 ACTION_SEARCH 인텐트가 검색 활동에 전달됩니다.

콘텐츠 제공자에 관해 확장하는 SearchRecentSuggestionsProvider 클래스가 이전 단계의 작업을 자동으로 처리하므로 작성할 코드가 거의 없습니다.

콘텐츠 제공업체 만들기

최근 추천 검색어에 필요한 콘텐츠 제공자는 SearchRecentSuggestionsProvider의 구현입니다. 이 클래스는 모든 작업을 자동으로 처리합니다. 코드 한 줄을 실행하는 클래스 생성자를 작성하기만 하면 됩니다.

예를 들어 최근 추천 검색어용 콘텐츠 제공자의 전체 구현은 다음과 같습니다.

Kotlin

class MySuggestionProvider : SearchRecentSuggestionsProvider() {
    init {
        setupSuggestions(AUTHORITY, MODE)
    }

    companion object {
        const val AUTHORITY = "com.example.MySuggestionProvider"
        const val MODE: Int = SearchRecentSuggestionsProvider.DATABASE_MODE_QUERIES
    }
}

자바

public class MySuggestionProvider extends SearchRecentSuggestionsProvider {
    public final static String AUTHORITY = "com.example.MySuggestionProvider";
    public final static int MODE = DATABASE_MODE_QUERIES;

    public MySuggestionProvider() {
        setupSuggestions(AUTHORITY, MODE);
    }
}

setupSuggestions() 호출은 검색 권한 및 데이터베이스 모드의 이름을 전달합니다. 검색 권한은 임의의 고유 문자열일 수 있지만 콘텐츠 제공자의 정규화된 이름(예: 패키지 이름 다음에 제공자의 클래스 이름 사용)을 사용하는 것이 좋습니다. 예: "com.example.MySuggestionProvider"

데이터베이스 모드는 DATABASE_MODE_QUERIES를 포함해야 하며 선택사항으로 추천 검색어 표에 각 추천 검색어와 함께 두 번째 텍스트 줄을 제공할 수 있는 열을 추가하는 DATABASE_MODE_2LINES를 포함할 수 있습니다. 각 추천 검색어에 두 줄을 제공하려면 다음 예시를 참고하세요.

Kotlin

const val MODE: Int = DATABASE_MODE_QUERIES or DATABASE_MODE_2LINES

자바

public final static int MODE = DATABASE_MODE_QUERIES | DATABASE_MODE_2LINES;

SearchRecentSuggestionsProvider 클래스와 검색 가능한 구성에 사용된 것과 동일한 권한 문자열을 사용하여 애플리케이션 매니페스트에서 콘텐츠 제공자를 선언합니다. 예를 들면 다음과 같습니다.

<application>
    <provider android:name=".MySuggestionProvider"
              android:authorities="com.example.MySuggestionProvider" />
    ...
</application>

검색 가능한 구성 수정

추천 검색어 제공자를 사용하도록 시스템을 구성하려면 검색 가능한 구성 파일의 <searchable> 요소에 android:searchSuggestAuthorityandroid:searchSuggestSelection 속성을 추가합니다. 예를 들면 다음과 같습니다.

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_label"
    android:hint="@string/search_hint"
    android:searchSuggestAuthority="com.example.MySuggestionProvider"
    android:searchSuggestSelection=" ?" >
</searchable>

android:searchSuggestAuthority의 값은 콘텐츠 제공자에 사용된 권한과 정확하게 일치하는 콘텐츠 제공자의 정규화된 이름이어야 합니다(예: 앞의 예에 나온 "com.example.MySuggestionProvider").

android:searchSuggestSelection의 값은 공백 뒤에 나오는 단일 물음표(" ?")여야 합니다. 이는 SQLite 선택 인수의 자리표시자이며 사용자가 입력하는 쿼리 텍스트로 자동으로 대체됩니다.

쿼리 저장

최근 쿼리 모음을 채우려면 검색 활동에 수신된 각 쿼리를 SearchRecentSuggestionsProvider에 추가합니다. 이렇게 하려면 검색 활동이 쿼리를 수신할 때마다 SearchRecentSuggestions 인스턴스를 만들고 saveRecentQuery()를 호출합니다. 예를 들어 활동의 onCreate() 메서드 중에 쿼리를 저장할 수 있는 방법은 다음과 같습니다.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)

    if (Intent.ACTION_SEARCH == intent.action) {
        intent.getStringExtra(SearchManager.QUERY)?.also { query ->
            SearchRecentSuggestions(this, MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE)
                    .saveRecentQuery(query, null)
        }
    }
}

자바

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Intent intent  = getIntent();

    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
        String query = intent.getStringExtra(SearchManager.QUERY);
        SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
                MySuggestionProvider.AUTHORITY, MySuggestionProvider.MODE);
        suggestions.saveRecentQuery(query, null);
    }
}

SearchRecentSuggestionsProvider 생성자에는 콘텐츠 제공자가 선언한 것과 동일한 권한 및 데이터베이스 모드가 필요합니다.

saveRecentQuery() 메서드는 검색어 문자열을 첫 번째 매개변수로 사용하고 선택사항으로 두 번째 문자열을 추천 검색어의 두 번째 줄(또는 null)로 포함합니다. 두 번째 매개변수는 DATABASE_MODE_2LINES로 추천 검색어에 두 줄 모드를 사용 설정한 경우에만 사용됩니다. 두 줄 모드를 사용 설정한 경우 시스템에서 일치하는 추천 검색어를 찾을 때 두 번째 줄에 관해서도 쿼리 텍스트의 일치 여부를 비교합니다.

추천 데이터 지우기

사용자의 개인 정보 보호를 위해 사용자가 최근 추천 검색어를 지울 수 있는 방법을 항상 제공해야 합니다. 쿼리 기록을 지우려면 clearHistory()를 호출합니다. 예를 들면 다음과 같습니다.

Kotlin

SearchRecentSuggestions(this, HelloSuggestionsProvider.AUTHORITY, HelloSuggestionsProvider.MODE)
        .clearHistory()

자바

SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
        HelloSuggestionProvider.AUTHORITY, HelloSuggestionProvider.MODE);
suggestions.clearHistory();

'검색 기록 지우기' 메뉴 항목, 환경설정 항목, 버튼 중에서 선택하여 위 예를 실행합니다. 사용자가 검색 기록을 삭제하기를 원하는지 확인하는 확인 대화상자를 제공합니다.