Wyszukiwanie w aplikacjach TV

Użytkownicy często mają na myśli konkretne treści, gdy korzystają z aplikacji do multimediów na telewizorze. Jeśli Twoja aplikacja zawiera duży katalog treści, wyszukiwanie konkretnego tytułu może nie być najlepszym sposobem na znalezienie tego, czego szukają użytkownicy. Interfejs wyszukiwania może pomóc użytkownikom znaleźć treści szybciej niż ich przeglądanie.

Biblioteka Leanback na Androidziex zawiera zestaw klas, które umożliwiają korzystanie ze standardowego interfejsu wyszukiwania w aplikacji. Jest on spójny z innymi funkcjami wyszukiwania na telewizorze i udostępnia takie funkcje jak rozpoznawanie mowy.

W tym przewodniku omówiono sposób udostępniania interfejsu wyszukiwania w aplikacji za pomocą klas biblioteki pomocy funkcji TalkBack.

Dodaj działanie związane z wyszukiwaniem

Jeśli do interfejsu przeglądania multimediów używasz klasy BrowseFragment, możesz włączyć interfejs wyszukiwania jako standardową część interfejsu. Interfejs wyszukiwania to ikona, która pojawia się w układzie, gdy ustawisz View.OnClickListener w obiekcie BrowseFragment. Poniższy przykładowy kod ilustruje tę metodę.

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ć, korzystając z metody setSearchAffordanceColor(int).

Dodawanie danych wejściowych i wyników wyszukiwania

Gdy użytkownik wybierze ikonę wyszukiwania, system wywoła działanie związane z wyszukiwaniem przy użyciu zdefiniowanej intencji. W przypadku aktywności związanej z wyszukiwaniem używaj układu liniowego zawierającego SearchFragment. Ten fragment musi też implementować interfejs SearchFragment.SearchResultProvider do wyświetlania wyników 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 powinien być używany z klasą SearchRunnable, która uruchamia zapytanie w oddzielnym wątku. Ta metoda sprawia, że potencjalnie wolno uruchomione zapytania nie blokują głównego wątku interfejsu.