Wyszukiwanie w aplikacjach TV

Gdy użytkownicy korzystają z aplikacji multimedialnej na telewizorze, często mają na myśli konkretne treści. Jeśli Twoja aplikacja zawiera duży katalog treści, przeglądanie w poszukiwaniu konkretnego tytułu może nie być najskuteczniejszym sposobem na znalezienie tego, czego szukają. Interfejs wyszukiwania może pomóc użytkownikom szybciej dotrzeć do interesujących ich treści niż przeglądanie.

Biblioteka androidx.leanback udostępnia zestaw klas, które umożliwiają włączenie w aplikacji standardowego interfejsu wyszukiwania zgodnego z innymi funkcjami wyszukiwania w telewizorze oraz funkcji takich jak wprowadzanie głosowe.

Z tego przewodnika dowiesz się, jak udostępnić w aplikacji interfejs wyszukiwania za pomocą klas biblioteki Leanback.

Dodawanie działania wyszukiwania

Gdy używasz klasy BrowseFragment do tworzenia interfejsu przeglądania multimediów, możesz włączyć interfejs wyszukiwania jako standardową część interfejsu użytkownika. Interfejs wyszukiwania to ikona, która pojawia się w układzie, gdy ustawisz View.OnClickListener na obiekcie BrowseFragment. Poniższy przykładowy kod pokazuje, jak to zrobić.

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

Uwaga: kolor ikony wyszukiwania możesz ustawić za pomocą metody setSearchAffordanceColor(int).

Dodawanie pola wyszukiwania i wyników

Gdy użytkownik wybierze ikonę wyszukiwania, system wywoła działanie wyszukiwania za pomocą zdefiniowanego intencji. W przypadku działania wyszukiwania użyj układu liniowego zawierającego element SearchFragment. Ten fragment musi też implementować interfejs SearchFragment.SearchResultProvider , aby wyświetlać wyniki wyszukiwania.

Poniższy przykładowy kod pokazuje, jak rozszerzyć klasę SearchFragment , aby udostępnić interfejs wyszukiwania i wyniki:

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

Poprzedni przykładowy kod jest przeznaczony do użycia z klasą SearchRunnable która uruchamia zapytanie wyszukiwania w osobnym wątku. Dzięki temu potencjalnie wolno działające zapytania nie blokują głównego wątku interfejsu użytkownika.