版权声明:本文为博主原创翻译文章,转载请注明出处。
推荐:
欢迎关注我创建的Android TV 专题,会定期给大家分享一些AndroidTv相关的内容:
https://www.jianshu.com/c/3f0ab61a1322
搜索功能实现
在前一章中介绍了Leanback支持库和UI相关实现的SearchFragment的用法。 在本章中,我将介绍(背景)搜索功能逻辑。
本章的大部分实现仅仅是对googlesamples的解释 。
应用内搜索算法
搜索算法在loadRows方法中实现,特别是主逻辑在AsyncTask的doInBackground方法中。 其实很简单,只需检查字符串“ 查询 ”是否包含在电影项目的标题或描述中。
UI相关任务适配器处理在UI线程中完成。 onPreExecute通过clear方法初始化包含搜索结果的mRowsAdapter。 搜索本身在doInBackground中的后台线程中执行 ,它使包含搜索结果的新的ListRow 。 这个listRow是通过onPostExecute方法添加到UI线程中的Adapter 。
SearchFragment.java
private void loadRows() {
// offload processing from the UI thread
new AsyncTask() {
private final String query = mQuery;
@Override
protected void onPreExecute() {
mRowsAdapter.clear();
}
@Override
protected ListRow doInBackground(String... params) {
final List result = new ArrayList<>();
for (Movie movie : mItems) {
// Main logic of search is here.
// Just check that "query" is contained in Title or Description or not.
if (movie.getTitle().toLowerCase(Locale.ENGLISH)
.contains(query.toLowerCase(Locale.ENGLISH))
|| movie.getDescription().toLowerCase(Locale.ENGLISH)
.contains(query.toLowerCase(Locale.ENGLISH))) {
result.add(movie);
}
}
ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
listRowAdapter.addAll(0, result);
HeaderItem header = new HeaderItem("Search Results");
return new ListRow(header, listRowAdapter);
}
@Override
protected void onPostExecute(ListRow listRow) {
mRowsAdapter.add(listRow);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
执行搜索
由于上面已经实现了搜索算法,我们只需要调用这个函数来获得搜索结果。
SearchFragment.java
@Override
public ObjectAdapter getResultsAdapter() {
Log.d(TAG, "getResultsAdapter");
// Delete previously implemented mock code.
// mRowsAdapter (Search result) is already prepared in loadRows method
return mRowsAdapter;
}
...
@Override
public boolean onQueryTextSubmit(String query) {
Log.i(TAG, String.format("Search Query Text Submit %s", query));
mQuery = query;
loadRows();
return true;
}
在onQueryTextSubmit方法中调用loadRows方法。 简单的实现已经完成了! 我们来尝试构建并运行代码。
搜索功能正常工作。
我们已经完成了搜索功能的最低执行。 下一步是即使在用户的文本输入过程中也能启用搜索。
动态搜索执行
为了检测用户输入搜索查询的时间,我们可以使用onQueryTextChange方法。 因此,基本概念是在onQueryTextChange中执行loadRows方法来实现动态(在用户输入期间)搜索。 但是,每当用户输入一个单词时,onQueryTextChange将被执行,并且在已经执行的时候不应该调用loadRows方法。 这里,Handler用于管理执行的loadRows方法。
SearchFragment.java
private static final long SEARCH_DELAY_MS = 1000L;
private final Handler mHandler = new Handler();
private final Runnable mDelayedLoad = new Runnable() {
@Override
public void run() {
loadRows();
}
};
...
/**
* Starts {@link #loadRows()} method after delay.
* @param query the word to be searched
* @param delay the time to wait until loadRows will be executed (milliseconds).
*/
private void loadQueryWithDelay(String query, long delay) {
mHandler.removeCallbacks(mDelayedLoad);
if (!TextUtils.isEmpty(query) && !query.equals("nil")) {
mQuery = query;
mHandler.postDelayed(mDelayedLoad, delay);
}
}
loadQueryWithDelay方法使用Handler以稍微延迟的方式发布loadRows任务,以便loadRows任务不会太频繁地执行。 最后一个修改是从onQueryTextChange调用此loadQueryWithDelay方法。
SearchFragment.java
@Override
public boolean onQueryTextChange(String newQuery){
Log.i(TAG, String.format("Search Query Text Change %s", newQuery));
loadQueryWithDelay(newQuery, SEARCH_DELAY_MS);
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
Log.i(TAG, String.format("Search Query Text Submit %s", query));
// No need to delay(wait) loadQuery, since the query typing has completed.
loadQueryWithDelay(query, 0);
return true;
}
Build and run
可以看出,即使在用户输入搜索查询时,搜索仍然执行。
视频播放器
源代码在github上。
关注微信公众号,定期为你推荐移动开发相关文章。