Tìm kiếm trong các ứng dụng trên TV

Người dùng thường nghĩ đến nội dung cụ thể khi sử dụng một ứng dụng đa phương tiện trên TV. Nếu ứng dụng của bạn chứa một danh mục nội dung lớn, thì việc duyệt qua một ứng dụng cụ thể có thể không phải là cách hiệu quả nhất để người dùng tìm thấy nội dung họ đang tìm kiếm. Giao diện tìm kiếm có thể giúp người dùng tìm được nội dung họ muốn nhanh hơn so với duyệt web.

Thư viện Leanback androidx cung cấp một tập hợp các lớp để hỗ trợ giao diện tìm kiếm chuẩn trong ứng dụng của bạn sao cho nhất quán với các chức năng tìm kiếm khác trên TV và cung cấp những tính năng như nhập bằng giọng nói.

Hướng dẫn này thảo luận cách cung cấp giao diện tìm kiếm trong ứng dụng bằng các lớp thư viện hỗ trợ Leanback.

Thêm hành động tìm kiếm

Khi sử dụng lớp BrowseFragment cho giao diện duyệt nội dung nghe nhìn, bạn có thể bật giao diện tìm kiếm dưới dạng phần tiêu chuẩn của giao diện người dùng. Giao diện tìm kiếm là một biểu tượng xuất hiện trong bố cục khi bạn đặt View.OnClickListener trên đối tượng BrowseFragment. Mã mẫu sau đây minh hoạ kỹ thuật này.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.browse_activity)
    browseFragment = fragmentManager.findFragmentById(R.id.browse_fragment) as BrowseFragment
    browseFragment.setOnSearchClickedListener { view ->
        val intent = Intent(this@BrowseActivity, SearchActivity::class.java)
        startActivity(intent)
    }

    browseFragment.setAdapter(buildAdapter())
}

Java

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

    browseFragment = (BrowseFragment)
            getFragmentManager().findFragmentById(R.id.browse_fragment);

    ...

    browseFragment.setOnSearchClickedListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(BrowseActivity.this, SearchActivity.class);
            startActivity(intent);
        }
    });

    browseFragment.setAdapter(buildAdapter());
}

Lưu ý: Bạn có thể đặt màu của biểu tượng tìm kiếm bằng cách sử dụng phương thức setSearchAffordanceColor(int).

Thêm nội dung tìm kiếm và kết quả

Khi người dùng chọn biểu tượng tìm kiếm, hệ thống sẽ gọi một hoạt động tìm kiếm bằng cách sử dụng ý định đã xác định. Đối với hoạt động tìm kiếm, hãy sử dụng bố cục tuyến tính có chứa SearchFragment. Mảnh này cũng phải triển khai giao diện SearchFragment.SearchResultProvider để hiển thị kết quả tìm kiếm.

Mã mẫu sau đây cho biết cách mở rộng lớp SearchFragment để cung cấp giao diện tìm kiếm và kết quả:

Kotlin

class MySearchFragment : SearchFragment(), SearchFragment.SearchResultProvider {
    private val rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
    private val handler = Handler()
    private val delayedLoad = SearchRunnable()

    val resultsAdapter: ObjectAdapter
    get() {
        return rowsAdapter
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setSearchResultProvider(this)
        setOnItemClickedListener(getDefaultItemClickedListener())
    }

    fun onQueryTextChange(newQuery: String): Boolean {
        rowsAdapter.clear()
        if (!TextUtils.isEmpty(newQuery)) {
            delayedLoad.setSearchQuery(newQuery)
            handler.removeCallbacks(delayedLoad)
            handler.postDelayed(delayedLoad, SEARCH_DELAY_MS)
        }
        return true
    }

    fun onQueryTextSubmit(query: String): Boolean {
        rowsAdapter.clear()
        if (!TextUtils.isEmpty(query)) {
            delayedLoad.setSearchQuery(query)
            handler.removeCallbacks(delayedLoad)
            handler.postDelayed(delayedLoad, SEARCH_DELAY_MS)
        }
        return true
    }

    companion object {
        private val SEARCH_DELAY_MS = 300
    }
}

Java

public class MySearchFragment extends SearchFragment
        implements SearchFragment.SearchResultProvider {

    private static final int SEARCH_DELAY_MS = 300;
    private ArrayObjectAdapter rowsAdapter;
    private Handler handler = new Handler();
    private SearchRunnable delayedLoad;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
        setSearchResultProvider(this);
        setOnItemClickedListener(getDefaultItemClickedListener());
        delayedLoad = new SearchRunnable();
    }

    @Override
    public ObjectAdapter getResultsAdapter() {
        return rowsAdapter;
    }

    @Override
    public boolean onQueryTextChange(String newQuery) {
        rowsAdapter.clear();
        if (!TextUtils.isEmpty(newQuery)) {
            delayedLoad.setSearchQuery(newQuery);
            handler.removeCallbacks(delayedLoad);
            handler.postDelayed(delayedLoad, SEARCH_DELAY_MS);
        }
        return true;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        rowsAdapter.clear();
        if (!TextUtils.isEmpty(query)) {
            delayedLoad.setSearchQuery(query);
            handler.removeCallbacks(delayedLoad);
            handler.postDelayed(delayedLoad, SEARCH_DELAY_MS);
        }
        return true;
    }
}

Mã ví dụ trước được dùng với lớp SearchRunnable chạy cụm từ tìm kiếm trên một luồng riêng. Kỹ thuật này ngăn các truy vấn có khả năng chạy chậm không chặn luồng giao diện người dùng chính.