Melakukan penelusuran di dalam aplikasi TV

Pengguna sering mengangankan konten tertentu saat menggunakan aplikasi media di TV. Jika aplikasi Anda berisi katalog konten yang besar, mencari judul tertentu mungkin bukan cara paling efisien bagi pengguna untuk menemukan konten yang mereka cari. Antarmuka penelusuran dapat membantu pengguna menemukan konten yang mereka inginkan lebih cepat daripada melakukan penjelajahan.

Library Leanback androidx menyediakan serangkaian class untuk mengaktifkan antarmuka penelusuran standar dalam aplikasi Anda yang konsisten dengan fungsi penelusuran lainnya di TV dan menyediakan berbagai fitur seperti input suara.

Panduan ini membahas cara menyediakan antarmuka penelusuran di aplikasi Anda menggunakan class support library Leanback.

Menambahkan tindakan penelusuran

Saat menggunakan class BrowseFragment untuk antarmuka penjelajahan media, Anda dapat mengaktifkan antarmuka penelusuran sebagai bagian standar dari antarmuka pengguna. Antarmuka penelusuran adalah ikon yang terlihat di tata letak saat Anda menetapkan View.OnClickListener pada objek BrowseFragment. Contoh kode berikut mendemonstrasikan teknik ini.

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());
}

Catatan: Anda dapat menetapkan warna ikon penelusuran menggunakan metode setSearchAffordanceColor(int).

Menambahkan input penelusuran dan hasil

Saat pengguna memilih ikon penelusuran, sistem akan memanggil aktivitas penelusuran menggunakan intent yang ditentukan. Untuk aktivitas penelusuran Anda, gunakan tata letak linear yang berisi SearchFragment. Fragmen ini juga harus mengimplementasikan antarmuka SearchFragment.SearchResultProvider untuk menampilkan hasil penelusuran.

Contoh kode berikut menunjukkan cara memperluas class SearchFragment untuk menyediakan antarmuka penelusuran dan hasil:

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;
    }
}

Kode contoh sebelumnya dimaksudkan untuk digunakan dengan class SearchRunnable yang menjalankan kueri penelusuran pada thread terpisah. Dengan teknik ini, kueri yang berpotensi berjalan lambat tidak akan memblokir thread antarmuka pengguna utama.