Thêm cụm từ tìm kiếm được đề xuất tuỳ chỉnh

Thử cách Compose
Jetpack Compose là bộ công cụ giao diện người dùng được đề xuất cho Android. Tìm hiểu cách thêm chức năng tìm kiếm trong Compose.

Khi sử dụng hộp thoại tìm kiếm hoặc tiện ích tìm kiếm của Android, bạn có thể cung cấp các đề xuất tìm kiếm tuỳ chỉnh được tạo từ dữ liệu trong ứng dụng của mình. Ví dụ: nếu ứng dụng của bạn là một từ điển, bạn có thể đề xuất các từ trong từ điển trùng khớp với văn bản được nhập vào trường tìm kiếm trước khi người dùng hoàn tất việc nhập cụm từ tìm kiếm. Những đề xuất này rất có giá trị vì chúng có thể dự đoán hiệu quả những gì người dùng muốn và cung cấp quyền truy cập tức thì vào nội dung đó. Hình 1 minh hoạ ví dụ về hộp thoại tìm kiếm có các đề xuất tuỳ chỉnh.

Sau khi cung cấp các đề xuất tuỳ chỉnh, bạn cũng có thể cung cấp các đề xuất đó cho Hộp tìm kiếm nhanh trên toàn hệ thống, cho phép truy cập vào nội dung của bạn từ bên ngoài ứng dụng.

Trước khi thêm đề xuất tuỳ chỉnh, hãy triển khai hộp thoại tìm kiếm Android hoặc một tiện ích tìm kiếm cho các lượt tìm kiếm trong ứng dụng của bạn. Hãy xem phần Tạo giao diện tìm kiếmTrình cung cấp nội dung.

Thông tin cơ bản

Hình 1. Ảnh chụp màn hình về một hộp thoại tìm kiếm có các cụm từ tìm kiếm được đề xuất tuỳ chỉnh.

Khi người dùng chọn một đề xuất tuỳ chỉnh, hệ thống sẽ gửi một Intent đến hoạt động có thể tìm kiếm của bạn. Không giống như một cụm từ tìm kiếm thông thường gửi ý định bằng thao tác ACTION_SEARCH, bạn có thể xác định các đề xuất tuỳ chỉnh để sử dụng ACTION_VIEW (hoặc bất kỳ thao tác ý định nào khác) và cũng bao gồm dữ liệu có liên quan đến đề xuất đã chọn. Trong ví dụ về từ điển, khi người dùng chọn một đề xuất, ứng dụng có thể mở ngay định nghĩa cho từ đó thay vì tìm kiếm các kết quả trùng khớp trong từ điển.

Để cung cấp đề xuất tuỳ chỉnh, hãy thực hiện các bước sau:

  • Triển khai một hoạt động cơ bản có thể tìm kiếm, như mô tả trong phần Tạo giao diện tìm kiếm.
  • Sửa đổi cấu hình có thể tìm kiếm bằng thông tin về nhà cung cấp nội dung cung cấp các đề xuất tuỳ chỉnh.
  • Tạo một bảng (chẳng hạn như trong SQLiteDatabase) cho các đề xuất của bạn và định dạng bảng bằng các cột bắt buộc.
  • Tạo một trình cung cấp nội dung có quyền truy cập vào bảng đề xuất của bạn và khai báo trình cung cấp đó trong tệp kê khai.
  • Khai báo loại Intent sẽ được gửi khi người dùng chọn một đề xuất, bao gồm cả thao tác tuỳ chỉnh và dữ liệu tuỳ chỉnh.

Tương tự như khi hệ thống Android hiển thị hộp thoại tìm kiếm, hệ thống cũng hiển thị các đề xuất tìm kiếm của bạn. Bạn cần một trình cung cấp nội dung mà hệ thống có thể truy xuất các đề xuất của bạn. Đọc phần Trình cung cấp nội dung để tìm hiểu cách tạo trình cung cấp nội dung.

Khi hệ thống xác định rằng hoạt động của bạn có thể tìm kiếm và đưa ra các đề xuất tìm kiếm, quy trình sau đây sẽ diễn ra khi người dùng nhập một cụm từ tìm kiếm:

  1. Hệ thống sẽ lấy văn bản của cụm từ tìm kiếm (tức là bất kỳ nội dung nào đã được nhập cho đến thời điểm này) và thực hiện một truy vấn đến trình cung cấp nội dung quản lý các đề xuất của bạn.
  2. Nhà cung cấp nội dung của bạn trả về một Cursor trỏ đến tất cả các đề xuất có liên quan đến văn bản cụm từ tìm kiếm.
  3. Hệ thống sẽ hiển thị danh sách các đề xuất do Cursor cung cấp.

Sau khi các đề xuất tuỳ chỉnh xuất hiện, có thể xảy ra những trường hợp sau:

  • Nếu người dùng nhập một chữ cái khác hoặc thay đổi cụm từ tìm kiếm theo bất kỳ cách nào, các bước trước đó sẽ lặp lại và danh sách đề xuất sẽ cập nhật cho phù hợp.
  • Nếu người dùng thực hiện tìm kiếm, các đề xuất sẽ bị bỏ qua và cụm từ tìm kiếm sẽ được gửi đến hoạt động có thể tìm kiếm của bạn bằng ý định ACTION_SEARCH thông thường.
  • Nếu người dùng chọn một đề xuất, thì một ý định sẽ được gửi đến hoạt động có thể tìm kiếm của bạn, mang theo một thao tác tuỳ chỉnh và dữ liệu tuỳ chỉnh để ứng dụng của bạn có thể mở nội dung được đề xuất.

Sửa đổi cấu hình có thể tìm kiếm

Để thêm tính năng hỗ trợ các đề xuất tuỳ chỉnh, hãy thêm thuộc tính android:searchSuggestAuthority vào phần tử <searchable> trong tệp cấu hình có thể tìm kiếm, như trong ví dụ sau:

<?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.MyCustomSuggestionProvider">
</searchable>

Bạn có thể cần thêm các thuộc tính, tuỳ thuộc vào loại ý định mà bạn đính kèm vào từng đề xuất và cách bạn muốn định dạng các truy vấn cho trình cung cấp nội dung. Các thuộc tính không bắt buộc khác sẽ được thảo luận trong các phần sau.

Tạo một trình cung cấp nội dung

Để tạo một trình cung cấp nội dung cho các đề xuất tuỳ chỉnh, trước tiên, hãy xem phần Trình cung cấp nội dung để tìm hiểu cách tạo một trình cung cấp nội dung. Trình cung cấp nội dung cho các đề xuất tuỳ chỉnh cũng tương tự như mọi trình cung cấp nội dung khác. Tuy nhiên, đối với mỗi đề xuất mà bạn cung cấp, hàng tương ứng trong Cursor phải bao gồm các cột cụ thể mà hệ thống hiểu và sử dụng để định dạng các đề xuất.

Khi người dùng nhập văn bản vào hộp thoại tìm kiếm hoặc tiện ích tìm kiếm, hệ thống sẽ truy vấn nhà cung cấp nội dung của bạn để tìm các đề xuất bằng cách gọi query() mỗi khi người dùng nhập một chữ cái. Khi triển khai query(), nhà cung cấp nội dung của bạn phải tìm kiếm dữ liệu đề xuất và trả về một Cursor trỏ đến các hàng mà nhà cung cấp nội dung xác định là đề xuất phù hợp.

Thông tin chi tiết về cách tạo trình cung cấp nội dung cho các đề xuất tuỳ chỉnh sẽ được thảo luận trong 2 phần sau:

Xử lý truy vấn đề xuất
Cách hệ thống gửi yêu cầu đến nhà cung cấp nội dung của bạn và cách xử lý các yêu cầu đó.
Tạo bảng đề xuất
Cách xác định các cột mà hệ thống mong đợi trong Cursor được trả về theo từng truy vấn.

Xử lý truy vấn đề xuất

Khi yêu cầu đề xuất từ trình cung cấp nội dung của bạn, hệ thống sẽ gọi phương thức query() của trình cung cấp nội dung. Triển khai phương thức này để tìm kiếm dữ liệu đề xuất và trả về một Cursor trỏ đến những đề xuất mà bạn cho là phù hợp.

Sau đây là thông tin tóm tắt về các tham số mà hệ thống truyền đến phương thức query() của bạn, được liệt kê theo thứ tự:

  1. uri

    Luôn là một nội dung Uri, được định dạng như sau:

    content://your.authority/optional.suggest.path/SUGGEST_URI_PATH_QUERY
    

    Hành vi mặc định là hệ thống sẽ truyền URI này và thêm văn bản truy vấn vào đó:

    content://your.authority/optional.suggest.path/SUGGEST_URI_PATH_QUERY/puppies
    

    Văn bản truy vấn ở cuối được mã hoá bằng các quy tắc mã hoá URI, vì vậy, bạn có thể cần phải giải mã văn bản đó trước khi thực hiện tìm kiếm.

    Phần optional.suggest.path chỉ được đưa vào URI nếu bạn đặt đường dẫn như vậy trong tệp cấu hình có thể tìm kiếm bằng thuộc tính android:searchSuggestPath. Bạn chỉ cần cung cấp thuộc tính này nếu sử dụng cùng một trình cung cấp nội dung cho nhiều hoạt động có thể tìm kiếm. Nếu đây là trường hợp này, hãy phân biệt nguồn của truy vấn đề xuất.

  2. projection
    Luôn rỗng.
  3. selection
    Giá trị được cung cấp trong thuộc tính android:searchSuggestSelection của tệp cấu hình có thể tìm kiếm hoặc giá trị rỗng nếu bạn không khai báo thuộc tính android:searchSuggestSelection. Phần tiếp theo sẽ thảo luận thêm về vấn đề này.
  4. selectionArgs
    Chứa cụm từ tìm kiếm dưới dạng phần tử đầu tiên và duy nhất của mảng nếu bạn khai báo thuộc tính android:searchSuggestSelection trong cấu hình có thể tìm kiếm. Nếu bạn không khai báo android:searchSuggestSelection, thì tham số này sẽ là rỗng. Phần tiếp theo sẽ thảo luận thêm về vấn đề này.
  5. sortOrder
    Luôn rỗng.

Hệ thống có thể gửi cho bạn văn bản cụm từ tìm kiếm theo hai cách. Cách mặc định là văn bản truy vấn được đưa vào làm đường dẫn cuối cùng của URI nội dung được truyền trong tham số uri. Tuy nhiên, nếu bạn thêm một giá trị lựa chọn vào thuộc tính android:searchSuggestSelection trong cấu hình có thể tìm kiếm, thì văn bản truy vấn sẽ được truyền dưới dạng phần tử đầu tiên của mảng chuỗi selectionArgs. Hai lựa chọn này sẽ được mô tả ở phần tiếp theo.

Lấy truy vấn trong Uri

Theo mặc định, truy vấn được thêm dưới dạng phân đoạn cuối cùng của tham số uri – một đối tượng Uri. Để truy xuất văn bản truy vấn trong trường hợp này, hãy sử dụng getLastPathSegment(), như minh hoạ trong ví dụ sau:

Kotlin

val query: String = uri.lastPathSegment.toLowerCase()

Java

String query = uri.getLastPathSegment().toLowerCase();

Thao tác này trả về phân đoạn cuối cùng của Uri, đó là văn bản truy vấn mà người dùng nhập.

Lấy truy vấn trong các đối số lựa chọn

Thay vì sử dụng URI, có thể sẽ hợp lý hơn nếu phương thức query() của bạn nhận được mọi thứ cần thiết để thực hiện tra cứu và bạn có thể muốn các tham số selectionselectionArgs mang các giá trị thích hợp. Trong trường hợp này, hãy thêm thuộc tính android:searchSuggestSelection vào cấu hình có thể tìm kiếm bằng chuỗi lựa chọn SQLite. Trong chuỗi lựa chọn, hãy thêm dấu chấm hỏi (?) làm trình giữ chỗ cho cụm từ tìm kiếm thực tế. Hệ thống gọi query() bằng chuỗi lựa chọn làm tham số selection và cụm từ tìm kiếm làm phần tử đầu tiên trong mảng selectionArgs.

Ví dụ: sau đây là cách bạn có thể tạo thuộc tính android:searchSuggestSelection để tạo một câu lệnh tìm kiếm toàn văn:

<?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.MyCustomSuggestionProvider"
    android:searchSuggestIntentAction="android.intent.action.VIEW"
    android:searchSuggestSelection="word MATCH ?">
</searchable>

Với cấu hình này, phương thức query() của bạn sẽ phân phối tham số selection dưới dạng "word MATCH ?" và tham số selectionArgs dưới dạng cụm từ tìm kiếm. Khi bạn truyền các đối số này đến một phương thức query() SQLite, các đối số này sẽ được tổng hợp với nhau, tức là dấu hỏi sẽ được thay thế bằng văn bản truy vấn. Nếu bạn nhận được các cụm từ tìm kiếm đề xuất theo cách này và cần thêm ký tự đại diện vào văn bản cụm từ tìm kiếm, hãy thêm hoặc đặt tiền tố cho các ký tự đó vào tham số selectionArgs, vì giá trị này được đặt trong dấu ngoặc kép và được chèn thay cho dấu chấm hỏi.

Một thuộc tính khác trong ví dụ trước là android:searchSuggestIntentAction, xác định thao tác theo ý định được gửi cùng với mỗi ý định khi người dùng chọn một đề xuất. Vấn đề này sẽ được thảo luận thêm trong phần Khai báo ý định cho các đề xuất.

Tạo bảng đề xuất

Khi bạn trả về các đề xuất cho hệ thống bằng Cursor, hệ thống sẽ yêu cầu các cột cụ thể trong mỗi hàng. Bất kể bạn lưu trữ dữ liệu đề xuất trong cơ sở dữ liệu SQLite trên thiết bị, cơ sở dữ liệu trên máy chủ web hay một định dạng khác trên thiết bị hoặc web, hãy định dạng các đề xuất dưới dạng hàng trong bảng và trình bày chúng bằng Cursor.

Hệ thống hiểu được một số cột, nhưng chỉ có 2 cột là bắt buộc:

_ID
Mã nhận dạng hàng là số nguyên duy nhất cho mỗi đề xuất. Hệ thống yêu cầu điều này để trình bày các đề xuất trong một ListView.
SUGGEST_COLUMN_TEXT_1
Chuỗi xuất hiện dưới dạng đề xuất.

Tất cả các cột sau đây đều không bắt buộc. Hầu hết các vấn đề này sẽ được thảo luận thêm trong các phần sau.

SUGGEST_COLUMN_TEXT_2
Một chuỗi. Nếu Cursor của bạn có cột này, thì tất cả các đề xuất sẽ được cung cấp ở định dạng hai dòng. Chuỗi trong cột này xuất hiện dưới dạng dòng văn bản thứ hai, nhỏ hơn bên dưới văn bản đề xuất chính. Giá trị này có thể là giá trị rỗng hoặc trống để cho biết không có văn bản phụ.
SUGGEST_COLUMN_ICON_1
Một tài nguyên có thể vẽ, nội dung hoặc chuỗi URI của tệp. Nếu Cursor của bạn có cột này, thì tất cả các đề xuất đều được cung cấp ở định dạng biểu tượng và văn bản, trong đó biểu tượng có thể vẽ ở bên trái. Giá trị này có thể là giá trị rỗng hoặc bằng 0 để cho biết không có biểu tượng trong hàng này.
SUGGEST_COLUMN_ICON_2
Một tài nguyên có thể vẽ, nội dung hoặc chuỗi URI của tệp. Nếu Cursor của bạn có cột này, thì tất cả các đề xuất đều được cung cấp ở định dạng biểu tượng và văn bản, trong đó biểu tượng nằm ở bên phải. Giá trị này có thể là null hoặc 0 để cho biết không có biểu tượng trong hàng này.
SUGGEST_COLUMN_INTENT_ACTION
Một chuỗi thao tác theo ý định. Nếu cột này tồn tại và chứa một giá trị tại hàng đã cho, thì thao tác được xác định ở đây sẽ được dùng khi tạo ý định của đề xuất. Nếu không có phần tử này, hành động sẽ được lấy từ trường android:searchSuggestIntentAction trong cấu hình có thể tìm kiếm của bạn. Nếu hành động của bạn giống nhau cho tất cả các đề xuất, thì việc chỉ định hành động bằng cách sử dụng android:searchSuggestIntentAction và bỏ qua cột này sẽ hiệu quả hơn.
SUGGEST_COLUMN_INTENT_DATA
Một chuỗi URI dữ liệu. Nếu cột này tồn tại và chứa một giá trị tại hàng đã cho, thì dữ liệu này sẽ được dùng khi tạo ý định của đề xuất. Nếu bạn không cung cấp phần tử này, dữ liệu sẽ được lấy từ trường android:searchSuggestIntentData trong cấu hình có thể tìm kiếm của bạn. Nếu không có nguồn nào được cung cấp, thì trường dữ liệu của ý định sẽ là giá trị rỗng. Nếu dữ liệu của bạn giống nhau cho tất cả các đề xuất hoặc có thể được mô tả bằng một phần không đổi và một mã nhận dạng cụ thể, thì bạn nên chỉ định dữ liệu đó bằng android:searchSuggestIntentData và bỏ qua cột này.
SUGGEST_COLUMN_INTENT_DATA_ID
Một chuỗi đường dẫn URI. Nếu cột này tồn tại và chứa một giá trị tại hàng đã cho, thì "/" và giá trị này sẽ được thêm vào trường dữ liệu trong ý định. Chỉ sử dụng thuộc tính này nếu trường dữ liệu do thuộc tính android:searchSuggestIntentData chỉ định trong cấu hình có thể tìm kiếm đã được đặt thành một chuỗi cơ sở thích hợp.
SUGGEST_COLUMN_INTENT_EXTRA_DATA
Dữ liệu tuỳ ý. Nếu cột này tồn tại và chứa một giá trị tại một hàng nhất định, thì đây là dữ liệu bổ sung được dùng khi tạo ý định đề xuất. Nếu không được cung cấp, trường dữ liệu bổ sung của ý định sẽ có giá trị rỗng. Cột này cho phép các đề xuất cung cấp dữ liệu bổ sung được đưa vào dưới dạng một phần bổ sung trong khoá EXTRA_DATA_KEY của ý định.
SUGGEST_COLUMN_QUERY
Nếu cột này tồn tại và phần tử này tồn tại ở hàng đã cho, thì đây là dữ liệu được dùng khi tạo truy vấn của đề xuất, được đưa vào dưới dạng một phần bổ sung trong khoá QUERY của ý định. Đây là thông số bắt buộc nếu hành động của đề xuất là ACTION_SEARCH, nhưng không bắt buộc trong trường hợp khác.
SUGGEST_COLUMN_SHORTCUT_ID
Chỉ dùng khi đưa ra đề xuất cho Hộp tìm kiếm nhanh. Cột này cho biết liệu một đề xuất tìm kiếm có phải được lưu trữ dưới dạng lối tắt hay không và liệu đề xuất đó có phải được xác thực hay không. Các lối tắt thường được tạo khi người dùng nhấn vào một đề xuất trong Hộp tìm kiếm nhanh. Nếu thiếu, kết quả sẽ được lưu trữ dưới dạng một lối tắt và không bao giờ được làm mới. Nếu bạn đặt thành SUGGEST_NEVER_MAKE_SHORTCUT, kết quả sẽ không được lưu trữ dưới dạng lối tắt. Nếu không, mã nhận dạng lối tắt sẽ được dùng để kiểm tra lại đề xuất mới nhất bằng cách sử dụng SUGGEST_URI_PATH_SHORTCUT.
SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING
Chỉ dùng khi đưa ra đề xuất cho Hộp tìm kiếm nhanh. Cột này chỉ định rằng một biểu tượng xoay phải xuất hiện thay vì một biểu tượng trong SUGGEST_COLUMN_ICON_2 trong khi lối tắt của đề xuất này đang làm mới trong Hộp tìm kiếm nhanh.

Hầu hết các cột này sẽ được thảo luận thêm trong các phần sau.

Khai báo ý định cho các đề xuất

Khi người dùng chọn một đề xuất trong danh sách xuất hiện bên dưới hộp thoại hoặc tiện ích tìm kiếm, hệ thống sẽ gửi một Intent tuỳ chỉnh đến hoạt động có thể tìm kiếm của bạn. Bạn phải xác định hành động và dữ liệu cho ý định.

Khai báo thao tác theo ý định

Hành động phổ biến nhất cho một đề xuất tuỳ chỉnh là ACTION_VIEW. Hành động này phù hợp khi bạn muốn mở một nội dung nào đó, chẳng hạn như định nghĩa của một từ, thông tin liên hệ của một người hoặc một trang web. Tuy nhiên, thao tác theo ý định có thể là bất kỳ thao tác nào khác và có thể khác nhau đối với từng đề xuất.

Tuỳ thuộc vào việc bạn muốn tất cả các đề xuất sử dụng cùng một thao tác theo ý định hay không, bạn có thể xác định thao tác theo hai cách:

  • Sử dụng thuộc tính android:searchSuggestIntentAction của tệp cấu hình có thể tìm kiếm để xác định thao tác cho tất cả các đề xuất, như trong ví dụ sau:
    <?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.MyCustomSuggestionProvider"
        android:searchSuggestIntentAction="android.intent.action.VIEW" >
    </searchable>
  • Sử dụng cột SUGGEST_COLUMN_INTENT_ACTION để xác định hành động cho từng đề xuất. Để thực hiện việc này, hãy thêm cột SUGGEST_COLUMN_INTENT_ACTION vào bảng đề xuất và đối với mỗi đề xuất, hãy đặt hành động cần sử dụng vào cột đó, chẳng hạn như "android.intent.action.VIEW".

Bạn cũng có thể kết hợp hai kỹ thuật này. Ví dụ: bạn có thể thêm thuộc tính android:searchSuggestIntentAction với một thao tác sẽ được dùng với tất cả các đề xuất theo mặc định, sau đó ghi đè thao tác này cho một số đề xuất bằng cách khai báo một thao tác khác trong cột SUGGEST_COLUMN_INTENT_ACTION. Nếu bạn không thêm giá trị vào cột SUGGEST_COLUMN_INTENT_ACTION, thì ý định mà bạn cung cấp trong thuộc tính android:searchSuggestIntentAction sẽ được sử dụng.

Khai báo dữ liệu về ý định

Khi người dùng chọn một đề xuất, hoạt động có thể tìm kiếm của bạn sẽ nhận được ý định với thao tác mà bạn xác định (như đã thảo luận trong phần trước), nhưng ý định cũng phải mang theo dữ liệu để hoạt động của bạn xác định đề xuất nào được chọn. Cụ thể, dữ liệu phải là một giá trị riêng biệt cho từng đề xuất, chẳng hạn như mã nhận dạng hàng cho đề xuất trong bảng SQLite của bạn. Khi nhận được ý định, bạn có thể truy xuất dữ liệu được đính kèm bằng getData() hoặc getDataString().

Bạn có thể xác định dữ liệu đi kèm với ý định theo 2 cách:

  • Xác định dữ liệu cho từng đề xuất trong cột SUGGEST_COLUMN_INTENT_DATA của bảng đề xuất.

    Cung cấp tất cả thông tin dữ liệu cần thiết cho từng ý định trong bảng đề xuất bằng cách thêm cột SUGGEST_COLUMN_INTENT_DATA rồi điền dữ liệu duy nhất cho từng hàng. Dữ liệu trong cột này được đính kèm vào ý định chính xác như bạn xác định trong cột này. Sau đó, bạn có thể truy xuất chuỗi này bằng getData() hoặc getDataString().

  • Phân mảnh một URI dữ liệu thành hai phần: phần chung cho tất cả các đề xuất và phần riêng cho từng đề xuất. Đặt các phần này vào thuộc tính android:searchSuggestintentData của cấu hình có thể tìm kiếm và cột SUGGEST_COLUMN_INTENT_DATA_ID của bảng đề xuất, tương ứng.

    Ví dụ sau đây cho biết cách khai báo phần URI chung cho tất cả các đề xuất trong thuộc tính android:searchSuggestIntentData của cấu hình có thể tìm kiếm:

      <?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.MyCustomSuggestionProvider"
          android:searchSuggestIntentAction="android.intent.action.VIEW"
          android:searchSuggestIntentData="content://com.example/datatable" >
      </searchable>
      

    Thêm đường dẫn cuối cùng cho từng đề xuất (phần duy nhất) vào cột SUGGEST_COLUMN_INTENT_DATA_ID trong bảng đề xuất. Khi người dùng chọn một đề xuất, hệ thống sẽ lấy chuỗi từ android:searchSuggestIntentData, thêm dấu gạch chéo (/), rồi thêm giá trị tương ứng từ cột SUGGEST_COLUMN_INTENT_DATA_ID để tạo thành một URI nội dung hoàn chỉnh. Sau đó, bạn có thể truy xuất Uri bằng getData().

Thêm dữ liệu khác

Nếu cần thể hiện thêm thông tin về ý định của mình, bạn có thể thêm một cột bảng khác, chẳng hạn như SUGGEST_COLUMN_INTENT_EXTRA_DATA. Cột này có thể lưu trữ thêm thông tin về đề xuất. Dữ liệu được lưu trong cột này sẽ được đặt trong EXTRA_DATA_KEY của gói bổ sung của ý định.

Xử lý ý định

Sau khi cung cấp các đề xuất tìm kiếm tuỳ chỉnh bằng ý định tuỳ chỉnh, bạn cần có hoạt động có thể tìm kiếm để xử lý các ý định này khi người dùng chọn một đề xuất. Đây là ngoài việc xử lý ý định ACTION_SEARCH mà hoạt động có thể tìm kiếm của bạn đã thực hiện. Dưới đây là ví dụ về cách bạn có thể xử lý các ý định trong lệnh gọi lại onCreate() của hoạt động:

Kotlin

when(intent.action) {
    Intent.ACTION_SEARCH -> {
        // Handle the normal search query case.
        intent.getStringExtra(SearchManager.QUERY)?.also { query ->
            doSearch(query)
        }
    }
    Intent.ACTION_VIEW -> {
        // Handle a suggestions click, because the suggestions all use ACTION_VIEW.
        showResult(intent.data)
    }
}

Java

Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
    // Handle the normal search query case.
    String query = intent.getStringExtra(SearchManager.QUERY);
    doSearch(query);
} else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
    // Handle a suggestions click, because the suggestions all use ACTION_VIEW.
    Uri data = intent.getData();
    showResult(data);
}

Trong ví dụ này, thao tác theo ý định là ACTION_VIEW và dữ liệu mang một URI hoàn chỉnh trỏ đến mục được đề xuất, như được tổng hợp bởi chuỗi android:searchSuggestIntentData và cột SUGGEST_COLUMN_INTENT_DATA_ID. Sau đó, URI sẽ truyền đến phương thức showResult() cục bộ. Phương thức này sẽ truy vấn nhà cung cấp nội dung cho mục do URI chỉ định.

Viết lại văn bản truy vấn

Theo mặc định, nếu người dùng di chuyển qua danh sách đề xuất bằng các nút điều khiển hướng, chẳng hạn như bằng bi xoay hoặc D-pad, thì văn bản truy vấn sẽ không cập nhật. Tuy nhiên, bạn có thể tạm thời viết lại văn bản truy vấn của người dùng khi văn bản đó xuất hiện trong hộp văn bản bằng một truy vấn khớp với đề xuất đang được lấy tiêu điểm. Điều này cho phép người dùng xem truy vấn được đề xuất, đồng thời họ có thể chọn hộp tìm kiếm và chỉnh sửa truy vấn trước khi gửi truy vấn đó dưới dạng một cụm từ tìm kiếm.

Bạn có thể viết lại văn bản truy vấn theo những cách sau:

  • Thêm thuộc tính android:searchMode vào cấu hình có thể tìm kiếm của bạn bằng giá trị "queryRewriteFromText". Trong trường hợp này, nội dung trong cột SUGGEST_COLUMN_TEXT_1 của đề xuất được dùng để viết lại văn bản truy vấn.
  • Thêm thuộc tính android:searchMode vào cấu hình có thể tìm kiếm của bạn bằng giá trị "queryRewriteFromData". Trong trường hợp này, nội dung trong cột SUGGEST_COLUMN_INTENT_DATA của đề xuất được dùng để viết lại văn bản truy vấn. Chỉ sử dụng phương thức này với các URI hoặc định dạng dữ liệu khác mà người dùng có thể thấy, chẳng hạn như URL HTTP. Đừng sử dụng các lược đồ URI nội bộ để viết lại truy vấn theo cách này.
  • Cung cấp một chuỗi văn bản truy vấn duy nhất trong cột SUGGEST_COLUMN_QUERY của bảng đề xuất. Nếu cột này xuất hiện và chứa một giá trị cho đề xuất hiện tại, thì giá trị đó sẽ được dùng để viết lại văn bản truy vấn và ghi đè một trong hai cách triển khai trước đó.

Hiển thị các cụm từ tìm kiếm được đề xuất cho Hộp tìm kiếm nhanh

Sau khi bạn định cấu hình ứng dụng để cung cấp các đề xuất tìm kiếm tuỳ chỉnh, việc cung cấp các đề xuất đó cho Hộp tìm kiếm nhanh có thể truy cập trên toàn cầu cũng dễ dàng như việc sửa đổi cấu hình có thể tìm kiếm để thêm android:includeInGlobalSearch với giá trị "true".

Trường hợp duy nhất cần thêm công việc là khi nhà cung cấp nội dung của bạn yêu cầu quyền đọc. Trong trường hợp đó, bạn cần thêm một phần tử <path-permission> để trình cung cấp cấp cho Hộp tìm kiếm nhanh quyền đọc đối với trình cung cấp nội dung của bạn, như minh hoạ trong ví dụ sau:

<provider android:name="MySuggestionProvider"
          android:authorities="com.example.MyCustomSuggestionProvider"
          android:readPermission="com.example.provider.READ_MY_DATA"
          android:writePermission="com.example.provider.WRITE_MY_DATA">
  <path-permission android:pathPrefix="/search_suggest_query"
                   android:readPermission="android.permission.GLOBAL_SEARCH" />
</provider>

Trong ví dụ này, nhà cung cấp hạn chế quyền đọc và ghi đối với nội dung. Phần tử <path-permission> sửa đổi quy định hạn chế bằng cách cấp quyền đọc cho nội dung bên trong tiền tố đường dẫn "/search_suggest_query" khi có quyền "android.permission.GLOBAL_SEARCH". Thao tác này cấp quyền truy cập vào Hộp tìm kiếm nhanh để hộp này có thể truy vấn nhà cung cấp nội dung của bạn để đưa ra đề xuất.

Nếu trình cung cấp nội dung của bạn không thực thi quyền đọc, thì Hộp tìm kiếm nhanh sẽ đọc quyền này theo mặc định.

Bật tính năng đề xuất trên thiết bị

Theo mặc định, các ứng dụng không được phép cung cấp đề xuất trong Hộp tìm kiếm nhanh, ngay cả khi chúng được định cấu hình để làm như vậy. Người dùng chọn có đưa đề xuất từ ứng dụng của bạn vào Hộp tìm kiếm nhanh hay không bằng cách mở Mục có thể tìm kiếm (nằm trong Cài đặt > Tìm kiếm) và bật ứng dụng của bạn làm mục có thể tìm kiếm.

Mỗi ứng dụng có trong Hộp tìm kiếm nhanh đều có một mục trong trang cài đặt Mục có thể tìm kiếm. Mục này bao gồm tên của ứng dụng và một đoạn mô tả ngắn về nội dung có thể tìm kiếm trong ứng dụng và được cung cấp để đề xuất trong Hộp tìm kiếm nhanh. Để xác định văn bản mô tả cho ứng dụng có thể tìm kiếm, hãy thêm thuộc tính android:searchSettingsDescription vào cấu hình có thể tìm kiếm, như trong ví dụ sau:

<?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.MyCustomSuggestionProvider"
    android:searchSuggestIntentAction="android.intent.action.VIEW"
    android:includeInGlobalSearch="true"
    android:searchSettingsDescription="@string/search_description" >
</searchable>

Hãy tạo chuỗi cho android:searchSettingsDescription ngắn gọn nhất có thể và nêu rõ nội dung có thể tìm kiếm. Ví dụ: "Nghệ sĩ, đĩa nhạc và bài hát" đối với ứng dụng nhạc hoặc "Ghi chú đã lưu" đối với ứng dụng ghi chú. Việc cung cấp nội dung mô tả này là rất quan trọng để người dùng biết loại đề xuất được cung cấp. Luôn thêm thuộc tính này khi android:includeInGlobalSearch là true.

Vì người dùng phải truy cập vào trình đơn cài đặt để bật tính năng đề xuất tìm kiếm cho ứng dụng của bạn, nên nếu tìm kiếm là một khía cạnh quan trọng của ứng dụng, hãy cân nhắc cách truyền đạt điều đó cho người dùng. Ví dụ: bạn có thể cung cấp một ghi chú trong lần đầu tiên người dùng khởi chạy ứng dụng để giải thích cách bật đề xuất tìm kiếm cho Hộp tìm kiếm nhanh.

Quản lý các lối tắt đề xuất của Hộp tìm kiếm nhanh

Những đề xuất mà người dùng chọn trong Hộp tìm kiếm nhanh có thể tự động trở thành lối tắt. Đây là những đề xuất mà hệ thống sao chép từ trình cung cấp nội dung của bạn để có thể nhanh chóng truy cập vào đề xuất mà không cần phải truy vấn lại trình cung cấp nội dung.

Theo mặc định, chế độ này được bật cho tất cả các đề xuất mà Hộp tìm kiếm nhanh truy xuất. Tuy nhiên, nếu dữ liệu đề xuất của bạn thay đổi theo thời gian, thì bạn có thể yêu cầu làm mới các lối tắt. Ví dụ: nếu các đề xuất của bạn đề cập đến dữ liệu động, chẳng hạn như trạng thái hiện diện của một người liên hệ, thì hãy yêu cầu làm mới các lối tắt đề xuất khi hiển thị cho người dùng. Để thực hiện việc này, hãy thêm SUGGEST_COLUMN_SHORTCUT_ID vào bảng đề xuất. Bạn có thể dùng cột này để định cấu hình hành vi của lối tắt cho từng đề xuất theo một trong những cách sau:

  • Khiến Hộp tìm kiếm nhanh truy vấn lại trình cung cấp nội dung của bạn để lấy phiên bản mới của lối tắt đề xuất.

    Cung cấp một giá trị trong cột SUGGEST_COLUMN_SHORTCUT_ID để truy vấn lại đề xuất cho phiên bản mới mỗi khi lối tắt xuất hiện. Lối tắt này nhanh chóng hiển thị bất kỳ dữ liệu nào có sẵn gần đây nhất cho đến khi truy vấn làm mới trả về. Tại thời điểm đó, đề xuất sẽ được làm mới bằng thông tin mới. Truy vấn làm mới được gửi đến trình cung cấp nội dung của bạn bằng đường dẫn URI là SUGGEST_URI_PATH_SHORTCUT thay vì SUGGEST_URI_PATH_QUERY.

    Hãy đảm bảo Cursor mà bạn trả về chứa một đề xuất bằng cách sử dụng cùng các cột như đề xuất ban đầu hoặc để trống, cho biết rằng lối tắt không còn hợp lệ. Trong trường hợp đó, đề xuất sẽ biến mất và lối tắt sẽ bị xoá.

    Nếu một đề xuất đề cập đến dữ liệu có thể mất nhiều thời gian hơn để làm mới, chẳng hạn như một lần làm mới dựa trên mạng, bạn cũng có thể thêm cột SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING vào bảng đề xuất với giá trị true để hiện một biểu tượng xoay tiến trình cho biểu tượng bên phải cho đến khi quá trình làm mới hoàn tất. Mọi giá trị không phải là true đều không hiển thị chỉ báo tiến trình.

  • Ngăn nội dung đề xuất bị sao chép vào một lối tắt.

    Cung cấp giá trị SUGGEST_NEVER_MAKE_SHORTCUT trong cột SUGGEST_COLUMN_SHORTCUT_ID. Trong trường hợp này, đề xuất sẽ không bao giờ được sao chép vào một lối tắt. Bạn chỉ cần làm việc này nếu hoàn toàn không muốn đề xuất đã sao chép trước đó xuất hiện. Nếu bạn cung cấp một giá trị bình thường cho cột, thì lối tắt đề xuất chỉ xuất hiện cho đến khi truy vấn làm mới trả về.

  • Cho phép áp dụng hành vi mặc định của lối tắt.

    Để trống SUGGEST_COLUMN_SHORTCUT_ID cho mỗi đề xuất không thay đổi và có thể lưu dưới dạng lối tắt.

Nếu không có đề xuất nào thay đổi, thì bạn không cần cột SUGGEST_COLUMN_SHORTCUT_ID.

Giới thiệu về thứ hạng đề xuất của Hộp tìm kiếm nhanh

Sau khi bạn cung cấp các đề xuất tìm kiếm của ứng dụng cho Hộp tìm kiếm nhanh, thứ hạng của Hộp tìm kiếm nhanh sẽ xác định cách các đề xuất được hiển thị cho người dùng đối với một cụm từ tìm kiếm cụ thể. Điều này có thể phụ thuộc vào số lượng ứng dụng khác có kết quả cho truy vấn đó và tần suất người dùng chọn kết quả của bạn so với kết quả của các ứng dụng khác. Không có gì đảm bảo về cách các đề xuất của bạn được xếp hạng hoặc liệu các đề xuất của ứng dụng có xuất hiện hay không cho một cụm từ tìm kiếm nhất định. Nhìn chung, việc cung cấp kết quả chất lượng sẽ làm tăng khả năng các đề xuất của ứng dụng xuất hiện ở vị trí nổi bật. Còn những ứng dụng cung cấp đề xuất chất lượng thấp có nhiều khả năng bị xếp hạng thấp hơn hoặc không hiển thị.