Tạo giao diện tìm kiếm

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 bạn đã sẵn sàng thêm chức năng tìm kiếm vào ứng dụng, Android sẽ giúp bạn triển khai giao diện người dùng bằng hộp thoại tìm kiếm xuất hiện ở đầu cửa sổ hoạt động hoặc một tiện ích tìm kiếm mà bạn có thể chèn vào bố cục. Cả hộp thoại tìm kiếm và tiện ích đều có thể gửi cụm từ tìm kiếm của người dùng đến một hoạt động cụ thể trong ứng dụng của bạn. Bằng cách này, người dùng có thể bắt đầu tìm kiếm từ bất kỳ hoạt động nào có hộp thoại tìm kiếm hoặc tiện ích, đồng thời hệ thống sẽ bắt đầu hoạt động thích hợp để thực hiện tìm kiếm và trình bày kết quả.

Các tính năng khác có sẵn cho hộp thoại và tiện ích tìm kiếm bao gồm:

  • Tìm kiếm bằng giọng nói
  • Đề xuất tìm kiếm dựa trên các cụm từ tìm kiếm gần đây
  • Đề xuất tìm kiếm khớp với kết quả thực tế trong dữ liệu ứng dụng của bạn

Tài liệu này hướng dẫn cách thiết lập ứng dụng để cung cấp một giao diện tìm kiếm được hệ thống Android hỗ trợ nhằm phân phối cụm từ tìm kiếm, bằng cách sử dụng hộp thoại tìm kiếm hoặc tiện ích tìm kiếm.

Tài nguyên có liên quan:

Thông tin cơ bản

Trước khi bắt đầu, hãy quyết định xem bạn muốn triển khai giao diện tìm kiếm bằng hộp thoại tìm kiếm hay tiện ích tìm kiếm. Chúng cung cấp các tính năng tìm kiếm giống nhau, nhưng theo cách hơi khác nhau:

  • Hộp thoại tìm kiếm là một thành phần giao diện người dùng do hệ thống Android kiểm soát. Khi người dùng kích hoạt, hộp thoại tìm kiếm sẽ xuất hiện ở đầu hoạt động.

    Hệ thống Android kiểm soát tất cả các sự kiện trong hộp thoại tìm kiếm. Khi người dùng gửi một cụm từ tìm kiếm, hệ thống sẽ gửi cụm từ tìm kiếm đó đến hoạt động mà bạn chỉ định để xử lý các lượt tìm kiếm. Hộp thoại này cũng có thể đưa ra các đề xuất tìm kiếm trong khi người dùng nhập.

  • Tiện ích tìm kiếm là một phiên bản của SearchView mà bạn có thể đặt ở bất cứ đâu trong bố cục của mình. Theo mặc định, tiện ích tìm kiếm hoạt động như một tiện ích EditText tiêu chuẩn và không làm gì cả, nhưng bạn có thể định cấu hình tiện ích này để hệ thống Android xử lý tất cả các sự kiện đầu vào, gửi truy vấn đến hoạt động thích hợp và cung cấp đề xuất tìm kiếm – giống như hộp thoại tìm kiếm.

Khi người dùng thực hiện một thao tác tìm kiếm từ hộp thoại tìm kiếm hoặc một tiện ích tìm kiếm, hệ thống sẽ tạo một Intent và lưu trữ cụm từ tìm kiếm của người dùng trong đó. Sau đó, hệ thống sẽ bắt đầu hoạt động mà bạn khai báo để xử lý các cụm từ tìm kiếm ("hoạt động có thể tìm kiếm") và gửi ý định đó. Để thiết lập ứng dụng cho loại tìm kiếm có trợ giúp này, bạn cần có những điều sau:

  • Cấu hình tìm kiếm
    Một tệp XML định cấu hình một số chế độ cài đặt cho hộp thoại hoặc tiện ích tìm kiếm. Trang này bao gồm các chế độ cài đặt cho những tính năng như tìm kiếm bằng giọng nói, đề xuất tìm kiếm và văn bản gợi ý cho hộp tìm kiếm.
  • Hoạt động có thể tìm kiếm
    Activity nhận cụm từ tìm kiếm, tìm kiếm dữ liệu của bạn và hiển thị kết quả tìm kiếm.
  • Giao diện tìm kiếm, do một trong những thành phần sau đây cung cấp:
    • Hộp thoại tìm kiếm
      Theo mặc định, hộp thoại tìm kiếm sẽ bị ẩn. Biểu tượng này xuất hiện ở đầu màn hình khi bạn gọi onSearchRequested() khi người dùng nhấn vào nút Tìm kiếm.
    • Tiện ích SearchView
      Việc sử dụng tiện ích tìm kiếm cho phép bạn đặt hộp tìm kiếm ở bất kỳ đâu trong hoạt động của mình, kể cả dưới dạng một khung hiển thị thao tác trong thanh ứng dụng.

Phần còn lại của tài liệu này sẽ hướng dẫn bạn cách tạo cấu hình tìm kiếm và hoạt động có thể tìm kiếm, cũng như cách triển khai giao diện tìm kiếm bằng hộp thoại tìm kiếm hoặc tiện ích tìm kiếm.

Tạo cấu hình có thể tìm kiếm

Điều đầu tiên bạn cần là một tệp XML có tên là cấu hình tìm kiếm. Thao tác này định cấu hình một số khía cạnh của giao diện người dùng trong hộp thoại hoặc tiện ích tìm kiếm và xác định cách hoạt động của các tính năng như đề xuất và tìm kiếm bằng giọng nói. Theo truyền thống, tệp này có tên là searchable.xml và phải được lưu trong thư mục dự án res/xml/.

Tệp cấu hình tìm kiếm phải có phần tử <searchable> làm nút gốc và chỉ định một hoặc nhiều thuộc tính, 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" >
</searchable>

Thuộc tính android:label là thuộc tính bắt buộc duy nhất. Nó trỏ đến một tài nguyên chuỗi, phải là tên ứng dụng. Nhãn này sẽ không xuất hiện cho người dùng cho đến khi bạn bật tính năng đề xuất tìm kiếm cho Hộp tìm kiếm nhanh. Lúc đó, nhãn này sẽ xuất hiện trong danh sách các mục có thể tìm kiếm trong phần cài đặt hệ thống.

Mặc dù không bắt buộc, nhưng bạn nên luôn thêm thuộc tính android:hint. Thuộc tính này cung cấp một chuỗi gợi ý trong hộp tìm kiếm trước khi người dùng nhập cụm từ tìm kiếm. Gợi ý này rất quan trọng vì nó cung cấp cho người dùng những manh mối quan trọng về nội dung mà họ có thể tìm kiếm.

Phần tử <searchable> chấp nhận một số thuộc tính khác. Tuy nhiên, bạn không cần hầu hết các thuộc tính cho đến khi thêm các tính năng như đề xuất tìm kiếmtìm kiếm bằng giọng nói. Để biết thông tin chi tiết về tệp cấu hình tìm kiếm, hãy xem tài liệu tham khảo về Cấu hình tìm kiếm.

Tạo một hoạt động có thể tìm kiếm

Hoạt động có thể tìm kiếm là Activity trong ứng dụng của bạn, thực hiện các lượt tìm kiếm dựa trên một chuỗi truy vấn và trình bày kết quả tìm kiếm.

Khi người dùng thực hiện một lượt tìm kiếm trong hộp thoại hoặc tiện ích tìm kiếm, hệ thống sẽ bắt đầu hoạt động có thể tìm kiếm của bạn và gửi cho hoạt động đó cụm từ tìm kiếm trong một Intent với thao tác ACTION_SEARCH. Hoạt động có thể tìm kiếm của bạn sẽ truy xuất cụm từ tìm kiếm từ phần bổ sung QUERY của ý định, sau đó tìm kiếm dữ liệu của bạn và trình bày kết quả.

Vì bạn có thể đưa hộp thoại hoặc tiện ích tìm kiếm vào bất kỳ hoạt động nào khác trong ứng dụng của mình, nên hệ thống phải biết hoạt động nào là hoạt động có thể tìm kiếm để có thể phân phối cụm từ tìm kiếm một cách thích hợp. Vì vậy, trước tiên, hãy khai báo hoạt động có thể tìm kiếm trong tệp kê khai Android.

Khai báo một hoạt động có thể tìm kiếm

Nếu bạn chưa có, hãy tạo một Activity thực hiện các lượt tìm kiếm và trình bày kết quả. Bạn chưa cần triển khai chức năng tìm kiếm, chỉ cần tạo một hoạt động mà bạn có thể khai báo trong tệp kê khai. Bên trong phần tử <activity> của tệp kê khai, hãy làm như sau:

  1. Khai báo hoạt động để chấp nhận ý định ACTION_SEARCH trong phần tử <intent-filter>.
  2. Chỉ định cấu hình tìm kiếm để sử dụng trong phần tử <meta-data>.

Lệnh này được minh hoạ trong ví dụ sau:

<application ... >
    <activity android:name=".SearchableActivity" >
        <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
        </intent-filter>
        <meta-data android:name="android.app.searchable"
                   android:resource="@xml/searchable"/>
    </activity>
    ...
</application>

Phần tử <meta-data> phải bao gồm thuộc tính android:name có giá trị là "android.app.searchable" và thuộc tính android:resource có giá trị tham chiếu đến tệp cấu hình có thể tìm kiếm. Trong ví dụ trước, thuộc tính này đề cập đến tệp res/xml/searchable.xml.

Thực hiện tìm kiếm

Sau khi bạn khai báo hoạt động có thể tìm kiếm trong tệp kê khai, hãy làm theo quy trình này để thực hiện tìm kiếm trong hoạt động có thể tìm kiếm:

  1. Nhận truy vấn.
  2. Tìm kiếm dữ liệu của bạn.
  3. Trình bày kết quả.

Nhận truy vấn

Khi người dùng thực hiện một lượt tìm kiếm từ hộp thoại hoặc tiện ích tìm kiếm, hệ thống sẽ khởi động hoạt động có thể tìm kiếm của bạn và gửi cho hoạt động đó một ý định ACTION_SEARCH. Ý định này mang theo cụm từ tìm kiếm trong chuỗi QUERY bổ sung. Kiểm tra ý định này khi hoạt động bắt đầu và trích xuất chuỗi. Ví dụ: sau đây là cách bạn có thể nhận được cụm từ tìm kiếm khi hoạt động có thể tìm kiếm của bạn bắt đầu:

Kotlin

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

    // Verify the action and get the query.
    if (Intent.ACTION_SEARCH == intent.action) {
        intent.getStringExtra(SearchManager.QUERY)?.also { query ->
            doMySearch(query)
        }
    }
}

Java

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

    // Get the intent, verify the action, and get the query.
    Intent intent = getIntent();
    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
      String query = intent.getStringExtra(SearchManager.QUERY);
      doMySearch(query);
    }
}

Chuỗi QUERY luôn được đưa vào ý định ACTION_SEARCH. Trong ví dụ trước, truy vấn được truy xuất và truyền đến một phương thức doMySearch() cục bộ, nơi thực hiện thao tác tìm kiếm thực tế.

Tìm kiếm dữ liệu của bạn

Quy trình lưu trữ và tìm kiếm dữ liệu là riêng biệt đối với ứng dụng của bạn. Bạn có thể lưu trữ và tìm kiếm dữ liệu theo nhiều cách và tài liệu này không hướng dẫn bạn cách thực hiện. Hãy cân nhắc cách bạn lưu trữ và tìm kiếm dữ liệu theo nhu cầu và định dạng dữ liệu của bạn. Sau đây là những mẹo bạn có thể áp dụng:

  • Nếu dữ liệu của bạn được lưu trữ trong cơ sở dữ liệu SQLite trên thiết bị, thì việc thực hiện một tìm kiếm toàn bộ văn bản (sử dụng FTS3 thay vì truy vấn LIKE) có thể cung cấp một hoạt động tìm kiếm mạnh mẽ hơn trên dữ liệu văn bản và có thể tạo ra kết quả nhanh hơn đáng kể. Hãy xem sqlite.org để biết thông tin về FTS3 và lớp SQLiteDatabase để biết thông tin về SQLite trên Android.
  • Nếu dữ liệu của bạn được lưu trữ trực tuyến, thì hiệu suất tìm kiếm mà người dùng cảm nhận được có thể bị ảnh hưởng bởi kết nối dữ liệu của người dùng. Bạn nên hiển thị một chỉ báo tiến trình cho đến khi kết quả tìm kiếm xuất hiện. Xem android.net để biết thông tin tham khảo về các API mạng và ProgressBar để biết thông tin về cách hiển thị chỉ báo tiến trình.

Trình bày kết quả

Bất kể dữ liệu của bạn nằm ở đâu và cách bạn tìm kiếm dữ liệu đó, bạn nên trả về kết quả tìm kiếm cho hoạt động có thể tìm kiếm của mình bằng Adapter. Bằng cách này, bạn có thể trình bày tất cả kết quả tìm kiếm trong một RecyclerView. Nếu dữ liệu của bạn đến từ một truy vấn cơ sở dữ liệu SQLite, bạn có thể áp dụng kết quả cho một RecyclerView bằng cách sử dụng CursorAdapter. Nếu dữ liệu của bạn có định dạng khác, thì bạn có thể tạo một tiện ích của BaseAdapter.

Adapter liên kết từng mục trong một tập dữ liệu thành một đối tượng View. Khi Adapter được áp dụng cho một RecyclerView, mỗi phần dữ liệu sẽ được chèn dưới dạng một khung hiển thị riêng vào danh sách. Adapter chỉ là một giao diện, vì vậy, bạn cần các phương thức triển khai như CursorAdapter (để liên kết dữ liệu từ Cursor). Nếu không có cách triển khai hiện tại nào phù hợp với dữ liệu của bạn, thì bạn có thể triển khai cách riêng của mình từ BaseAdapter.

Sử dụng hộp thoại tìm kiếm

Hộp thoại tìm kiếm cung cấp một hộp tìm kiếm nổi ở đầu màn hình, có biểu tượng ứng dụng ở bên trái. Hộp thoại tìm kiếm có thể đưa ra các đề xuất tìm kiếm khi người dùng nhập. Khi người dùng thực hiện một tìm kiếm, hệ thống sẽ gửi cụm từ tìm kiếm đến một hoạt động có thể tìm kiếm để thực hiện tìm kiếm.

Theo mặc định, hộp thoại tìm kiếm luôn bị ẩn cho đến khi người dùng kích hoạt. Ứng dụng có thể kích hoạt hộp thoại tìm kiếm bằng cách gọi onSearchRequested(). Tuy nhiên, phương thức này sẽ không hoạt động cho đến khi bạn bật hộp thoại tìm kiếm cho hoạt động.

Để cho phép hộp thoại tìm kiếm thực hiện các hoạt động tìm kiếm, hãy cho hệ thống biết hoạt động có thể tìm kiếm nào phải nhận các truy vấn tìm kiếm từ hộp thoại tìm kiếm. Ví dụ: trong phần trước về tạo một hoạt động có thể tìm kiếm, một hoạt động có thể tìm kiếm có tên là SearchableActivity sẽ được tạo. Nếu bạn muốn một hoạt động riêng biệt (chẳng hạn như hoạt động có tên OtherActivity) để hiện hộp thoại tìm kiếm và phân phối nội dung tìm kiếm đến SearchableActivity, hãy khai báo trong tệp kê khai rằng SearchableActivity là hoạt động có thể tìm kiếm để dùng cho hộp thoại tìm kiếm trong OtherActivity.

Để khai báo hoạt động có thể tìm kiếm cho hộp thoại tìm kiếm của một hoạt động, hãy thêm phần tử <meta-data> vào bên trong phần tử <activity> của hoạt động tương ứng. Phần tử <meta-data> phải bao gồm thuộc tính android:value chỉ định tên lớp của hoạt động có thể tìm kiếm và thuộc tính android:name có giá trị là "android.app.default_searchable".

Ví dụ: sau đây là nội dung khai báo cho cả hoạt động có thể tìm kiếm (SearchableActivity) và một hoạt động khác (OtherActivity) sử dụng SearchableActivity để thực hiện các cụm từ tìm kiếm được thực thi từ hộp thoại tìm kiếm của hoạt động đó:

<application ... >
    <!-- This is the searchable activity; it performs searches. -->
    <activity android:name=".SearchableActivity" >
        <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
        </intent-filter>
        <meta-data android:name="android.app.searchable"
                   android:resource="@xml/searchable"/>
    </activity>

    <!-- This activity enables the search dialog to initiate searches
         in the SearchableActivity. -->
    <activity android:name=".OtherActivity" ... >
        <!-- Enable the search dialog to send searches to SearchableActivity. -->
        <meta-data android:name="android.app.default_searchable"
                   android:value=".SearchableActivity" />
    </activity>
    ...
</application>

OtherActivity hiện bao gồm một phần tử <meta-data> để khai báo hoạt động có thể tìm kiếm nào sẽ dùng cho các lượt tìm kiếm, nên hoạt động này sẽ bật hộp thoại tìm kiếm. Mặc dù người dùng đang ở trong hoạt động này, nhưng phương thức onSearchRequested() sẽ kích hoạt hộp thoại tìm kiếm. Khi người dùng thực hiện tìm kiếm, hệ thống sẽ bắt đầu SearchableActivity và gửi cho hệ thống đó ý định ACTION_SEARCH.

Nếu bạn muốn mọi hoạt động trong ứng dụng của mình đều cung cấp hộp thoại tìm kiếm, hãy chèn phần tử <meta-data> trước đó làm phần tử con của phần tử <application>, thay vì từng <activity>. Bằng cách này, mọi hoạt động đều kế thừa giá trị, cung cấp hộp thoại tìm kiếm và gửi nội dung tìm kiếm đến cùng một hoạt động có thể tìm kiếm. Nếu có nhiều hoạt động có thể tìm kiếm, bạn có thể ghi đè hoạt động có thể tìm kiếm mặc định bằng cách đặt một khai báo <meta-data> khác bên trong các hoạt động riêng lẻ.

Khi hộp thoại tìm kiếm đã được bật cho các hoạt động của bạn, ứng dụng của bạn đã sẵn sàng thực hiện các hoạt động tìm kiếm.

Gọi hộp thoại tìm kiếm

Mặc dù một số thiết bị có nút tìm kiếm chuyên dụng, nhưng hành vi của nút này có thể khác nhau giữa các thiết bị và nhiều thiết bị hoàn toàn không có nút tìm kiếm. Vì vậy, khi sử dụng hộp thoại tìm kiếm, bạn phải cung cấp một nút tìm kiếm trong giao diện người dùng để kích hoạt hộp thoại tìm kiếm bằng cách gọi onSearchRequested().

Ví dụ: thêm một nút tìm kiếm vào trình đơn tuỳ chọn hoặc bố cục giao diện người dùng gọi onSearchRequested().

Bạn cũng có thể bật chức năng "nhập để tìm kiếm". Chức năng này sẽ kích hoạt hộp thoại tìm kiếm khi người dùng bắt đầu nhập trên bàn phím. Các tổ hợp phím sẽ được chèn vào hộp thoại tìm kiếm. Bạn có thể bật tính năng nhập để tìm kiếm trong hoạt động bằng cách gọi setDefaultKeyMode hoặc DEFAULT_KEYS_SEARCH_LOCAL trong phương thức onCreate() của hoạt động.

Tác động của hộp thoại tìm kiếm đến vòng đời hoạt động

Hộp thoại tìm kiếm là một Dialog nổi ở đầu màn hình. Thao tác này không gây ra bất kỳ thay đổi nào trong ngăn xếp hoạt động, vì vậy, khi hộp thoại tìm kiếm xuất hiện, không có phương thức vòng đời nào (chẳng hạn như onPause()) được gọi. Hoạt động của bạn mất tiêu điểm nhập vì tiêu điểm nhập được chuyển cho hộp thoại tìm kiếm.

Nếu muốn nhận thông báo khi hộp thoại tìm kiếm được kích hoạt, hãy ghi đè phương thức onSearchRequested(). Khi hệ thống gọi phương thức này, tức là hoạt động của bạn mất tiêu điểm đầu vào vào hộp thoại tìm kiếm, vì vậy, bạn có thể thực hiện mọi thao tác phù hợp cho sự kiện này, chẳng hạn như tạm dừng trò chơi. Trừ phi bạn đang truyền dữ liệu ngữ cảnh tìm kiếm (được thảo luận trong một phần khác của tài liệu này), hãy kết thúc phương thức bằng cách gọi quá trình triển khai siêu lớp:

Kotlin

override fun onSearchRequested(): Boolean {
    pauseSomeStuff()
    return super.onSearchRequested()
}

Java

@Override
public boolean onSearchRequested() {
    pauseSomeStuff();
    return super.onSearchRequested();
}

Nếu người dùng huỷ tìm kiếm bằng cách nhấn vào nút Quay lại, hộp thoại tìm kiếm sẽ đóng và hoạt động lấy lại tiêu điểm nhập. Bạn có thể đăng ký nhận thông báo khi hộp thoại tìm kiếm đóng bằng setOnDismissListener(), setOnCancelListener() hoặc cả hai. Bạn chỉ cần đăng ký OnDismissListener vì phương thức này được gọi mỗi khi hộp thoại tìm kiếm đóng. OnCancelListener chỉ liên quan đến những sự kiện mà người dùng thoát khỏi hộp thoại tìm kiếm một cách rõ ràng, vì vậy, sự kiện này không được gọi khi một lượt tìm kiếm được thực hiện. Khi bạn thực hiện tìm kiếm, hộp thoại tìm kiếm sẽ tự động biến mất.

Nếu hoạt động hiện tại không phải là hoạt động có thể tìm kiếm, thì các sự kiện vòng đời hoạt động thông thường sẽ được kích hoạt khi người dùng thực hiện một thao tác tìm kiếm – hoạt động hiện tại sẽ nhận được onPause(), như mô tả trong phần Giới thiệu về các hoạt động. Tuy nhiên, nếu hoạt động hiện tại là hoạt động có thể tìm kiếm, thì một trong hai điều sau sẽ xảy ra:

  • Theo mặc định, hoạt động có thể tìm kiếm sẽ nhận được ý định ACTION_SEARCH bằng một lệnh gọi đến onCreate() và một phiên bản mới của hoạt động sẽ được đưa lên đầu ngăn xếp hoạt động. Hiện có 2 phiên bản của hoạt động có thể tìm kiếm trong ngăn xếp hoạt động, vì vậy, khi nhấn vào nút Quay lại, bạn sẽ quay lại phiên bản trước của hoạt động có thể tìm kiếm, thay vì thoát khỏi hoạt động có thể tìm kiếm.
  • Nếu bạn đặt android:launchMode thành "singleTop", thì hoạt động có thể tìm kiếm sẽ nhận được ý định ACTION_SEARCH bằng một lệnh gọi đến onNewIntent(Intent), truyền ý định ACTION_SEARCH mới. Ví dụ: sau đây là cách bạn có thể xử lý trường hợp này, trong đó chế độ khởi chạy của hoạt động có thể tìm kiếm là "singleTop":

    Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.search)
        handleIntent(intent)
    }
    
    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        handleIntent(intent)
    }
    
    private fun handleIntent(intent: Intent) {
        if (Intent.ACTION_SEARCH == intent.action) {
            intent.getStringExtra(SearchManager.QUERY)?.also { query ->
                doMySearch(query)
            }
        }
    }

    Java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search);
        handleIntent(getIntent());
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        handleIntent(intent);
    }
    
    private void handleIntent(Intent intent) {
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
          String query = intent.getStringExtra(SearchManager.QUERY);
          doMySearch(query);
        }
    }

    So với mã ví dụ trong phần về thực hiện một lượt tìm kiếm, tất cả mã để xử lý ý định tìm kiếm hiện nằm trong phương thức handleIntent(), để cả onCreate()onNewIntent() đều có thể thực thi mã này.

    Khi hệ thống gọi onNewIntent(Intent), hoạt động sẽ không khởi động lại, vì vậy phương thức getIntent() sẽ trả về cùng một ý định nhận được bằng onCreate(). Đó là lý do bạn phải gọi setIntent(Intent) bên trong onNewIntent(Intent): để ý định do hoạt động lưu được cập nhật trong trường hợp bạn gọi getIntent() trong tương lai.

Thông thường, bạn nên dùng trường hợp thứ hai (chế độ chạy "singleTop"), vì sau khi tìm kiếm xong, người dùng có thể thực hiện các lượt tìm kiếm khác và bạn không muốn ứng dụng của mình tạo nhiều phiên bản của hoạt động có thể tìm kiếm. Bạn nên đặt hoạt động có thể tìm kiếm ở chế độ khởi chạy "singleTop" trong bảng kê khai ứng dụng, như minh hoạ trong ví dụ sau:

<activity android:name=".SearchableActivity"
          android:launchMode="singleTop" >
    <intent-filter>
        <action android:name="android.intent.action.SEARCH" />
    </intent-filter>
    <meta-data
          android:name="android.app.searchable"
          android:resource="@xml/searchable"/>
  </activity>

Truyền dữ liệu ngữ cảnh tìm kiếm

Trong một số trường hợp, bạn có thể tinh chỉnh cụm từ tìm kiếm cần thiết trong hoạt động có thể tìm kiếm cho mỗi lượt tìm kiếm. Tuy nhiên, nếu muốn tinh chỉnh tiêu chí tìm kiếm dựa trên hoạt động mà người dùng đang thực hiện tìm kiếm, bạn có thể cung cấp thêm dữ liệu trong ý định mà hệ thống gửi đến hoạt động có thể tìm kiếm của bạn. Bạn có thể truyền dữ liệu bổ sung trong APP_DATA Bundle. Dữ liệu này có trong ý định ACTION_SEARCH.

Để truyền loại dữ liệu này đến hoạt động có thể tìm kiếm, hãy ghi đè phương thức onSearchRequested() cho hoạt động mà người dùng có thể thực hiện tìm kiếm, tạo Bundle bằng dữ liệu bổ sung và gọi startSearch() để kích hoạt hộp thoại tìm kiếm. Ví dụ:

Kotlin

override fun onSearchRequested(): Boolean {
    val appData = Bundle().apply {
        putBoolean(JARGON, true)
    }
    startSearch(null, false, appData, false)
    return true
}

Java

@Override
public boolean onSearchRequested() {
     Bundle appData = new Bundle();
     appData.putBoolean(SearchableActivity.JARGON, true);
     startSearch(null, false, appData, false);
     return true;
 }

Việc trả về giá trị true cho biết bạn đã xử lý thành công sự kiện gọi lại này và gọi startSearch() để kích hoạt hộp thoại tìm kiếm. Sau khi người dùng gửi một cụm từ tìm kiếm, cụm từ đó sẽ được gửi đến hoạt động có thể tìm kiếm của bạn cùng với dữ liệu mà bạn thêm. Bạn có thể trích xuất dữ liệu bổ sung từ APP_DATA Bundle để tinh chỉnh nội dung tìm kiếm, như trong ví dụ sau:

Kotlin

val jargon: Boolean = intent.getBundleExtra(SearchManager.APP_DATA)?.getBoolean(JARGON) ?: false

Java

Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
if (appData != null) {
    boolean jargon = appData.getBoolean(SearchableActivity.JARGON);
}

Sử dụng tiện ích tìm kiếm

Hình ảnh cho thấy chế độ xem tìm kiếm trong thanh trên cùng của ứng dụng

Hình 1. Tiện ích SearchView dưới dạng khung hiển thị hành động trên thanh ứng dụng.

Tiện ích tìm kiếm cung cấp chức năng tương tự như hộp thoại tìm kiếm. Thao tác này sẽ bắt đầu hoạt động thích hợp khi người dùng thực hiện một lượt tìm kiếm, đồng thời có thể đưa ra các đề xuất tìm kiếm và thực hiện tìm kiếm bằng giọng nói. Nếu không thể đặt tiện ích tìm kiếm trong thanh ứng dụng, bạn có thể đặt tiện ích tìm kiếm ở một vị trí nào đó trong bố cục hoạt động.

Định cấu hình tiện ích tìm kiếm

Sau khi bạn tạo một cấu hình tìm kiếm và một hoạt động có thể tìm kiếm, hãy bật tính năng tìm kiếm có hỗ trợ cho từng SearchView bằng cách gọi setSearchableInfo() và truyền cho tính năng này đối tượng SearchableInfo đại diện cho cấu hình có thể tìm kiếm của bạn.

Bạn có thể tham chiếu đến SearchableInfo bằng cách gọi getSearchableInfo() trên SearchManager.

Ví dụ: nếu bạn đang sử dụng SearchView làm khung hiển thị hành động trong thanh ứng dụng, hãy bật tiện ích trong lệnh gọi lại onCreateOptionsMenu(), như minh hoạ trong ví dụ sau:

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    // Inflate the options menu from XML.
    val inflater = menuInflater
    inflater.inflate(R.menu.options_menu, menu)

    // Get the SearchView and set the searchable configuration.
    val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
    (menu.findItem(R.id.menu_search).actionView as SearchView).apply {
        // Assumes current activity is the searchable activity.
        setSearchableInfo(searchManager.getSearchableInfo(componentName))
        setIconifiedByDefault(false) // Don't iconify the widget. Expand it by default.
    }

    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the options menu from XML.
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.options_menu, menu);

    // Get the SearchView and set the searchable configuration.
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
    // Assumes current activity is the searchable activity.
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
    searchView.setIconifiedByDefault(false); // Don't iconify the widget. Expand it by default.

    return true;
}

Tiện ích tìm kiếm hiện đã được định cấu hình và hệ thống sẽ gửi các cụm từ tìm kiếm đến hoạt động có thể tìm kiếm của bạn. Bạn cũng có thể bật đề xuất tìm kiếm cho tiện ích tìm kiếm.

Để biết thêm thông tin về thành phần hiển thị hành động trong thanh ứng dụng, hãy xem phần Sử dụng thành phần hiển thị hành động và trình cung cấp hành động.

Các tính năng khác của tiện ích tìm kiếm

Tiện ích SearchView cung cấp một số tính năng bổ sung mà bạn có thể muốn:

Nút gửi
Theo mặc định, không có nút nào để gửi cụm từ tìm kiếm, vì vậy, người dùng phải nhấn phím Return (Quay lại) trên bàn phím để bắt đầu tìm kiếm. Bạn có thể thêm nút "gửi" bằng cách gọi setSubmitButtonEnabled(true).
Tinh chỉnh cụm từ tìm kiếm cho cụm từ tìm kiếm được đề xuất
Khi bật tính năng đề xuất tìm kiếm, bạn thường mong đợi người dùng chọn một đề xuất, nhưng họ cũng có thể muốn tinh chỉnh cụm từ tìm kiếm được đề xuất. Bạn có thể thêm một nút bên cạnh mỗi đề xuất để chèn đề xuất đó vào hộp tìm kiếm để người dùng tinh chỉnh bằng cách gọi setQueryRefinementEnabled(true).
Khả năng bật/tắt chế độ hiển thị của hộp tìm kiếm
Theo mặc định, tiện ích tìm kiếm sẽ được "biểu tượng hoá", tức là chỉ được biểu thị bằng một biểu tượng tìm kiếm (kính lúp). Biểu tượng này sẽ mở rộng để hiện hộp tìm kiếm khi người dùng nhấn vào biểu tượng. Như trong ví dụ trước, theo mặc định, bạn có thể cho thấy hộp tìm kiếm bằng cách gọi setIconifiedByDefault(false). Bạn cũng có thể bật/tắt giao diện của tiện ích tìm kiếm bằng cách gọi setIconified().

Có một số API khác trong lớp SearchView cho phép bạn tuỳ chỉnh tiện ích tìm kiếm. Tuy nhiên, hầu hết các phương thức này chỉ được dùng khi bạn tự xử lý mọi dữ liệu đầu vào của người dùng, thay vì dùng hệ thống Android để phân phối cụm từ tìm kiếm và hiển thị đề xuất tìm kiếm.

Sử dụng cả tiện ích và hộp thoại

Nếu bạn chèn tiện ích tìm kiếm vào thanh ứng dụng dưới dạng một khung hiển thị thao tác và cho phép tiện ích này xuất hiện trong thanh ứng dụng nếu có chỗ trống (bằng cách đặt android:showAsAction="ifRoom"), thì tiện ích tìm kiếm có thể không xuất hiện dưới dạng một khung hiển thị thao tác. Thay vào đó, một mục trong trình đơn có thể xuất hiện trong trình đơn mục bổ sung. Ví dụ: khi ứng dụng của bạn chạy trên màn hình nhỏ hơn, có thể không có đủ chỗ trong thanh ứng dụng để hiển thị tiện ích tìm kiếm cùng với các mục hành động hoặc phần tử điều hướng khác, vì vậy, mục trong trình đơn sẽ xuất hiện trong trình đơn mục bổ sung. Khi được đặt trong trình đơn mục bổ sung, mục này hoạt động như một mục trình đơn thông thường và không hiển thị khung hiển thị thao tác, tức là tiện ích tìm kiếm.

Để xử lý tình huống này, mục trong trình đơn mà bạn đính kèm tiện ích tìm kiếm phải kích hoạt hộp thoại tìm kiếm khi người dùng chọn mục đó trong trình đơn mục bổ sung. Để thực hiện việc này, hãy triển khai onOptionsItemSelected() để xử lý mục trình đơn "Tìm kiếm" và mở hộp thoại tìm kiếm bằng cách gọi onSearchRequested().

Để biết thêm thông tin về cách hoạt động của các mục trong thanh ứng dụng và cách xử lý tình huống này, hãy xem phần Thêm thanh ứng dụng.

Thêm tính năng tìm kiếm bằng giọng nói

Bạn có thể thêm chức năng tìm kiếm bằng giọng nói vào hộp thoại hoặc tiện ích tìm kiếm bằng cách thêm thuộc tính android:voiceSearchMode vào cấu hình có thể tìm kiếm. Thao tác này sẽ thêm một nút tìm kiếm bằng giọng nói để khởi chạy lời nhắc bằng giọng nói. Khi người dùng nói xong, cụm từ tìm kiếm được phiên âm sẽ được gửi đến hoạt động có thể tìm kiếm của bạn.

Lệnh này được minh hoạ trong ví dụ sau:

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search_label"
    android:hint="@string/search_hint"
    android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" >
</searchable>

Bạn phải nhập giá trị showVoiceSearchButton để bật tính năng tìm kiếm bằng giọng nói. Giá trị thứ hai, launchRecognizer, chỉ định rằng nút tìm kiếm bằng giọng nói phải khởi chạy một trình nhận dạng trả về văn bản được chép lời cho hoạt động có thể tìm kiếm.

Bạn có thể cung cấp các thuộc tính bổ sung để chỉ định hành vi tìm kiếm bằng giọng nói, chẳng hạn như ngôn ngữ dự kiến và số lượng kết quả tối đa cần trả về. Hãy xem tài liệu tham khảo về Cấu hình tìm kiếm để biết thêm thông tin về các thuộc tính có sẵn.

Thêm cụm từ tìm kiếm được đề xuất

Cả hộp thoại tìm kiếm và tiện ích tìm kiếm đều có thể cung cấp đề xuất tìm kiếm khi người dùng nhập, với sự trợ giúp của hệ thống Android. Hệ thống quản lý danh sách đề xuất và xử lý sự kiện khi người dùng chọn một đề xuất.

Bạn có thể cung cấp hai loại đề xuất tìm kiếm:

Đề xuất tìm kiếm cho cụm từ tìm kiếm gần đây
Đây là những từ mà người dùng đã từng sử dụng làm cụm từ tìm kiếm trong ứng dụng của bạn. Hãy xem phần Thêm đề xuất tìm kiếm tuỳ chỉnh để biết thêm thông tin.
Đề xuất tìm kiếm tuỳ chỉnh
Đây là những cụm từ tìm kiếm được đề xuất mà bạn cung cấp từ nguồn dữ liệu của riêng mình để giúp người dùng chọn ngay cách viết chính xác hoặc mục mà họ đang tìm kiếm. Hãy xem bài viết Thêm đề xuất tìm kiếm tuỳ chỉnh để biết thêm thông tin.