
文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载当用户在 TV 上使用媒体应用时脑中往往已经有明确的想看内容。如果应用的内容目录足够庞大让用户逐行浏览来寻找某个特定标题显然不是最有效的路径。为应用内置一个搜索界面是帮助用户快速定位内容、缩短从坐到沙发上到开始播放之间距离的关键手段。本文以《Android 官方培训课程中文版》的 TV 应用内搜索 课程对应仓库文档 tv/discovery/in-app-search.md为核心完整讲解如何利用 Leanback 支持库在 TV 应用中构建标准搜索界面从BrowseFragment的搜索入口到SearchFragment的搜索输入与结果展示并给出可直接复制的 Java 实现代码。读完本文你将能够为 TV 应用接入一套与 Android TV 全局搜索风格一致、支持语音输入、且不会阻塞主线程的完整应用内搜索方案。为什么 TV 应用需要应用内搜索TV 设备为用户提供了大量娱乐选择——数千个应用和相关内容服务。与此同时大多数用户希望用尽量少的遥控器操作来观看内容理想场景是坐下、开机、直接观看。这意味着应用必须提供快速、容易的内容发现路径。Android 官方培训课程的 TV 内容发现专题 将内容发现归纳为三条路径推荐 TV 内容通过推荐服务将内容推送到 TV 主屏幕的推荐栏见 tv/discovery/recommendations.md使 TV 应用可被搜索实现 Content Provider 与searchable.xml让应用内容出现在 Android TV 全局搜索中见 tv/discovery/searchable.mdTV 应用内搜索即本文主题——在应用内部使用一套为 TV 优化的内置搜索界面。后两条路径解决的是不同问题全局搜索负责让用户在整个系统层面发现你的内容而应用内搜索则服务于用户已经打开你的应用、想在大目录里快速找到特定内容的场景。Leanback 支持库TV 搜索界面的标准实现Android 为 TV 界面开发提供了 v17 Leanback 支持库。该库提供了一整套面向大屏、焦点导航优化的组件媒体浏览用BrowseFragment详见 tv/playback/browse.md 中的创建目录浏览器一节详情展示用DetailsFragment详见 tv/playback/details.md而应用内搜索则对应SearchFragment及其配套接口SearchFragment.SearchResultProvider。使用 Leanback 库实现应用内搜索有两个核心收益一致性搜索界面与其他 TV 搜索功能外观、交互逻辑统一用户学习成本低内置语音输入TV 遥控器上的语音搜索可无缝接入无需自行实现语音识别 UI。整个应用内搜索的架构由两部分组成搜索入口——挂在浏览界面BrowseFragment上的搜索图标搜索页面——承载SearchFragment的独立 Activity负责接收输入、执行查询并展示结果。第一步在 BrowseFragment 中添加搜索入口当应用使用BrowseFragment作为媒体浏览界面时可以非常轻量地启用搜索入口。方法是在BrowseFragment对象上设置一个View.OnClickListener——一旦设置搜索图标就会作为界面的标准组成部分出现在布局中。以下代码展示了这一技巧来自原文档 tv/discovery/in-app-search.md 的完整示例Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.browse_activity); mBrowseFragment (BrowseFragment) getFragmentManager().findFragmentById(R.id.browse_fragment); ... mBrowseFragment.setOnSearchClickedListener(new View.OnClickListener() { Override public void onClick(View view) { Intent intent new Intent(BrowseActivity.this, SearchActivity.class); startActivity(intent); } }); mBrowseFragment.setAdapter(buildAdapter()); }要点说明R.id.browse_fragment对应布局中声明的BrowseFragment控件。在 tv/playback/browse.md 中可以找到对应的布局写法在LinearLayout内放置fragment android:nameandroid.support.v17.leanback.app.BrowseFragment android:idid/browse_fragment .../点击搜索图标时通过Intent显式启动承载搜索界面的SearchActivity需在 AndroidManifest.xml 中注册该 ActivitysetAdapter(buildAdapter())用于设置浏览界面的数据适配器ArrayObjectAdapterListRowPresenter它与搜索入口相互独立但共同组成完整的浏览页面。Note搜索图标的颜色可以通过setSearchAffordanceColor(int)方法自定义传入一个颜色资源或整型颜色值即可使搜索入口与应用主题色保持一致。第二步创建搜索 Activity 与 SearchFragment 布局当用户选中搜索图标后系统通过前面定义的 Intent 启动搜索 Activity。搜索 Activity 的布局应该使用一个线性布局LinearLayout其中包含一个SearchFragment。关键约束在于这个 Fragment 必须实现SearchFragment.SearchResultProvider接口否则无法显示搜索结果。一个典型的搜索 Activity 实现如下public class SearchActivity extends Activity { Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_activity); // 线性布局 SearchFragment } }对应的res/layout/search_activity.xml布局结构示意LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical fragment android:namecom.example.android.mediabrowser.MySearchFragment android:idid/search_fragment android:layout_widthmatch_parent android:layout_heightmatch_parent / /LinearLayout同时在 AndroidManifest.xml 中声明搜索 Activity参照 tv/playback/details.md 中对 Activity 的声明方式TV 应用建议搭配 Leanback 主题activity android:name.SearchActivity android:exportedtrue android:themestyle/Theme.Leanback /第三步扩展 SearchFragment 并实现 SearchResultProvider接下来是核心部分扩展SearchFragment类同时实现SearchFragment.SearchResultProvider接口提供搜索输入接收与结果展示能力。以下代码是原文档的完整示例建议直接作为实现模板public class MySearchFragment extends SearchFragment implements SearchFragment.SearchResultProvider { private static final int SEARCH_DELAY_MS 300; private ArrayObjectAdapter mRowsAdapter; private Handler mHandler new Handler(); private SearchRunnable mDelayedLoad; Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mRowsAdapter new ArrayObjectAdapter(new ListRowPresenter()); setSearchResultProvider(this); setOnItemClickedListener(getDefaultItemClickedListener()); mDelayedLoad new SearchRunnable(); } Override public ObjectAdapter getResultsAdapter() { return mRowsAdapter; } Override public boolean onQueryTextChange(String newQuery) { mRowsAdapter.clear(); if (!TextUtils.isEmpty(newQuery)) { mDelayedLoad.setSearchQuery(newQuery); mHandler.removeCallbacks(mDelayedLoad); mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS); } return true; } Override public boolean onQueryTextSubmit(String query) { mRowsAdapter.clear(); if (!TextUtils.isEmpty(query)) { mDelayedLoad.setSearchQuery(query); mHandler.removeCallbacks(mDelayedLoad); mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS); } return true; } }各成员与方法的职责拆解成员 / 方法职责mRowsAdapterArrayObjectAdapterListRowPresenter构建的行适配器承载搜索结果的多行数据setSearchResultProvider(this)将当前 Fragment 注册为结果提供者框架会回调其getResultsAdapter()获取结果getResultsAdapter()返回展示搜索结果的ObjectAdapter框架据此渲染列表onQueryTextChange(String)用户每输入/修改一个字符都会被回调即时搜索场景onQueryTextSubmit(String)用户提交查询按下确认/搜索键时回调SEARCH_DELAY_MS 300输入防抖延迟300ms 内连续输入只触发最后一次查询避免高频重复查询TextUtils.isEmpty()空查询时直接清空结果行并提前返回不发起无效搜索防抖Debounce机制为什么重要onQueryTextChange在用户逐字输入时会被频繁调用。若每次都立即执行数据库或网络查询会产生大量无效请求。示例中的做法是立即mRowsAdapter.clear()清空旧结果保证界面不残留过期内容将最新查询词写入SearchRunnablemHandler.removeCallbacks(mDelayedLoad)取消上一次尚未执行的搜索任务mHandler.postDelayed(mDelayedLoad, SEARCH_DELAY_MS)在 300ms 后执行。这样只有用户停止输入 300ms 后才会真正发起搜索兼顾了响应速度与查询开销。第四步在后台线程执行搜索SearchRunnable原文档特别强调上面的示例代码需要配合一个独立的SearchRunnable类使用由它在单独的线程上运行搜索查询。这一技巧的核心目的是让可能很慢的查询数据库检索、网络请求不阻塞主 UI 线程避免界面卡顿甚至 ANR。SearchRunnable的职责边界如下典型实现模式public class SearchRunnable implements Runnable { private volatile String mQuery; public void setSearchQuery(String query) { mQuery query; } Override public void run() { // 在非主线程中执行真正的查询数据库 / 网络 // 1. 根据 mQuery 检索内容库 // 2. 将结果封装为 ListRow 数据 // 3. 通过 Handler 回到主线程更新 mRowsAdapter } }实现时的关键考量线程切换postDelayed触发run()时仍在主线程上因此run()内部应再启动后台线程如Thread、AsyncTask或线程池执行耗时查询查询完成后通过Handler或runOnUiThread切回主线程更新mRowsAdapter并发防护使用volatile关键字修饰查询词保证跨线程可见性并在提交结果前比对当前查询词是否仍是最新值丢弃过期结果防止后发先至导致的错乱查询词校验onQueryTextChange与onQueryTextSubmit均已通过TextUtils.isEmpty拦截空串run()内可再做一次防御性检查。从搜索到播放点击结果的后续链路搜索界面只完成找到内容这一步点击结果后的跳转逻辑由setOnItemClickedListener(getDefaultItemClickedListener())挂载的监听器负责。一个完整 TV 应用的典型链路是用户点击某个搜索结果监听器解析该结果对应的媒体条目 ID / 数据携带数据启动详情页或直接播放页。详情页的构建方式可参考 tv/playback/details.md使用DetailsFragmentDetailsOverviewRowPresenter展示标题、描述、预览图与购买 / 租赁等操作按钮。原文档同时给出了一个值得采纳的产品建议能直接跳转到播放界面时尽量直接播放为用户省去一两次多余点击——这与 TV 用户最少操作的偏好完全一致。与全局搜索searchable的分工配合需要明确区分的是应用内搜索本文与使 TV 应用可被搜索tv/discovery/searchable.md是两套机制维度应用内搜索全局搜索可搜索性入口位置应用内部的BrowseFragment搜索图标Android TV 主屏幕的全局搜索框核心组件SearchFragmentSearchResultProviderContentProvidersearchable.xmlACTION_SEARCH处理 Activity适用场景用户在应用内快速定位内容用户在系统层面发现应用内容必要字段无强制字段要求SUGGEST_COLUMN_TEXT_1、SUGGEST_COLUMN_CONTENT_TYPE、SUGGEST_COLUMN_PRODUCTION_YEAR必须提供两者共享同一个底层搜索理念且可以共用同一套内容索引与查询逻辑如searchable.md中VideoContentProvider.query()getSuggestions()的检索方式同样可复用于应用内搜索的后台查询。一个成熟的 TV 媒体应用通常会同时启用两者全局搜索负责拉新应用内搜索负责承接用户已进入应用后的查找诉求。推荐内容tv/discovery/recommendations.md则负责主动推送三者共同构成完整的 TV 内容发现体系。实现清单与最佳实践总结将原文档的课程内容落地到真实项目时可按以下清单自查搜索入口在BrowseFragment上调用setOnSearchClickedListener(...)点击后启动搜索 Activity如需个性化用setSearchAffordanceColor(int)调整图标颜色搜索页面搜索 Activity 使用线性布局承载SearchFragmentFragment 必须实现SearchFragment.SearchResultProvider结果数据在getResultsAdapter()中返回基于ArrayObjectAdapterListRowPresenter的行适配器输入处理同时实现onQueryTextChange与onQueryTextSubmit非空查询才发起搜索空查询立即清空结果性能引入 300ms 左右的输入防抖HandlerpostDelayed并将真正耗时的查询放入后台线程执行严禁在主线程做数据库或网络检索结果跳转通过setOnItemClickedListener处理点击携带媒体数据跳转详情页或直接播放Manifest 配置确保搜索 Activity 已注册并选用合适的 Leanback 主题。按照上述步骤即可为 TV 应用构建出一套标准、高效、可语音输入、不卡顿的应用内搜索体验。后续可继续学习 创建 TV 游戏应用 等专题进一步完善 TV 应用矩阵。赞分享文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载相关推荐Android TV 播放应用开发基于 Leanback 库的媒体详情页DetailsFragment完整实战Android TV 播放应用开发基于 Leanback 库的媒体详情页DetailsFragment完整实战 本篇技术指南聚焦于「创建 TV 播放应用」文档教程移动开发Android TV 内容发现指南主屏推荐、全局搜索与 Leanback 应用内搜索Android 官方培训课程中文版Android TV 内容发现指南主屏推荐、全局搜索与 Leanback 应用内搜索Android 官方培训课程中文版 本文整理自「Android 官方培文档教程移动开发Android TV 播放应用构建指南基于 Leanback 库的浏览、卡片、详情与正在播放实现Android TV 播放应用构建指南基于 Leanback 库的浏览、卡片、详情与正在播放实现 本指南基于「Android官方培训课程中文版」仓库中 tv/文档教程移动开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考