[译]SearchFragment --Android TV 开发手册十二

版权声明:本文为博主原创翻译文章,转载请注明出处。

推荐:
欢迎关注我创建的Android TV 专题,会定期给大家分享一些AndroidTv相关的内容:
https://www.jianshu.com/c/3f0ab61a1322


[译]SearchFragment --Android TV 开发手册十二_第1张图片
search

Android TV 应用内搜寻

Android手机和Android TV之间最大的区别之一就是他们的输入法。 由于电视不支持触摸板,我们不应该期望用户使用电视键盘,为电视输入字词很麻烦。

Google建议在电视应用中使用语音输入进行搜索

BrowseFragment上的应用内搜索图标

BrowseFragment包含搜索功能的设计布局,并且在应用程序上显示应用内图标非常简单。 只需要实现setOnSearchClickedListener就可以了。

// Existence of this method make In-app search icon visible
   setOnSearchClickedListener(new View.OnClickListener() {
         @Override
         public void onClick(View view) {
                
          }
     });

setSearchAffordanceColor方法可用于指定搜索图标颜色。

  // set search icon color
  setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));
[译]SearchFragment --Android TV 开发手册十二_第2张图片
search1

当调用setOnSearchClickedListener时,应用内搜索图标将显示在BrowseFragment的右上角。

SearchFragment

需要实现搜索功能来回答用户的搜索查询。 为了显示搜索查询输入UI和搜索结果UI,LeanbackLibrary提供了SearchFragment。 这一次,当请求搜索(通过语音搜索按钮或显式按搜索按钮图标)时,我们从SearchActivity调用此SearchFragment。

private void setupEventListeners() {
        setOnItemViewSelectedListener(new ItemViewSelectedListener());
        setOnItemViewClickedListener(new ItemViewClickedListener());

        // Existence of this method make In-app search icon visible
        setOnSearchClickedListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(getActivity(), SearchActivity.class);
                startActivity(intent);
            }
        });
    }

通过右键单击包名称 Create → New Activity → Blank Activity →键入“SearchActivity”,开始创建SearchActivity。 在创建了SearchActivity类和activity_search.xml布局之后,按如下所示修改res / acitivity_search.xml。




它附加SearchFragment。 再次,通过Create → New → Java class → SearchFragment,并使其成为android.support.v17.leanback.app.SearchFragment的子类。

如果您在这里构建和运行应用程序,则应用程序将崩溃,因为SearchFragment会自动从内部语音识别器开始获取搜索查询。

实现语音输入/语音搜索 - setSpeechRecognitionCallback

官方文件说,

如果您不通过setSpeechRecognitionCallback(SpeechRecognitionCallback)提供回调,则将使用内部语音识别器,您的应用程序将需要它来请求android.permission.RECORD_AUDIO。

所以你需要:

  • 实现setSpeechRecognitionCallback
  • 在AndroidManifest.xml上请求android.permission.RECORD_AUDIO

如下。

public class SearchFragment extends android.support.v17.leanback.app.SearchFragment {

    private static final String TAG = SearchFragment.class.getSimpleName();

    private static final int REQUEST_SPEECH = 0x00000010;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (!Utils.hasPermission(getActivity(), Manifest.permission.RECORD_AUDIO)) {
            // SpeechRecognitionCallback is not required and if not provided recognition will be handled
            // using internal speech recognizer, in which case you must have RECORD_AUDIO permission
            setSpeechRecognitionCallback(new SpeechRecognitionCallback() {
                @Override
                public void recognizeSpeech() {
                    Log.v(TAG, "recognizeSpeech");
                    try {
                        startActivityForResult(getRecognizerIntent(), REQUEST_SPEECH);
                    } catch (ActivityNotFoundException e) {
                        Log.e(TAG, "Cannot find activity for speech recognizer", e);
                    }
                }
            });
        }
    }

utils.java

    public static boolean hasPermission(final Context context, final String permission) {
        return PackageManager.PERMISSION_GRANTED == context.getPackageManager().checkPermission(
                permission, context.getPackageName());
    }

覆盖onSearchRequeseted以激活应用内搜索

当用户尝试语音输入搜索时,执行onSearchRequested回调,默认情况下将启动Google的全局内容搜索。


[译]SearchFragment --Android TV 开发手册十二_第3张图片
search2

语音搜索功能与Google的默认语音搜索结果相关。

如果要激活应用内应用程序搜索,则需要重写此方法。

它是写在startSearch方法的描述中

它通常从onSearchRequested()直接从Activity.onSearchRequested()或任何给定的Activity中的覆盖版本调用。 如果您的目标只是激活搜索,则最好调用onSearchRequested(),这可能已被您的Activity中的其他地方覆盖。 如果您的目标是注入上下文数据等特定数据,则优先覆盖onSearchRequested(),以便任何调用者将从覆盖中获益。

我们覆盖MainActivity和SearchActivity的onSearchRequested方法。

    @Override
    public boolean onSearchRequested() {
        startActivity(new Intent(this, SearchActivity.class));
        return true;
    }

自定义应用内搜索 - SearchResultProvider

SearchResultProvider接口是Leanback库的接口,用于监听搜索相关事件。 我们需要重写3种方法。

  • getResultsAdapter - 返回包含搜索结果的适配器,以显示SearchFragment上的搜索结果。
  • onQueryTextChange - 当用户更改搜索查询文本时调用的事件侦听器。
  • onQueryTextSubmit - 当用户提交搜索查询文本时调用的事件侦听器。

我们需要使用setSearchResultProvider方法注册这个SearchResultProvider,最小化的实现就是这样,

public class SearchFragment extends android.support.v17.leanback.app.SearchFragment
        implements android.support.v17.leanback.app.SearchFragment.SearchResultProvider {

    private static final String TAG = SearchFragment.class.getSimpleName();

    private static final int REQUEST_SPEECH = 0x00000010;
    private ArrayObjectAdapter mRowsAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());

        setSearchResultProvider(this);

        ...
    }

    ... 

    @Override
    public ObjectAdapter getResultsAdapter() {
        Log.d(TAG, "getResultsAdapter");
        Log.d(TAG, mRowsAdapter.toString());

        // It should return search result here,
        // but static Movie Item list will be returned here now for practice.
        ArrayList mItems = MovieProvider.getMovieItems();
        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
        listRowAdapter.addAll(0, mItems);
        HeaderItem header = new HeaderItem("Search results");
        mRowsAdapter.add(new ListRow(header, listRowAdapter));

        return mRowsAdapter;
    }

    @Override
    public boolean onQueryTextChange(String newQuery){
        Log.i(TAG, String.format("Search Query Text Change %s", newQuery));
        return true;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        Log.i(TAG, String.format("Search Query Text Submit %s", query));
        return true;
    }

构建并运行

SearchActivity可以通过两种方式启动,

1.单击BrowseFragment的搜索图标。
2.当用户从特定控制器启动语音输入搜索*1(将调用onSearchRequested。)

*1这取决于Android TV设备。 例如,SONY BRAVIA提供触摸板遥控器,可以从该遥控器完成语音搜索。


[译]SearchFragment --Android TV 开发手册十二_第4张图片
OneTouchPadRemote

SearchFragment现在显示模拟搜索结果。

[译]SearchFragment --Android TV 开发手册十二_第5张图片
search3

源码在 github上。

我们应该实现OnItemViewClickedListener来定义点击这些搜索结果的动作。 这个OnItemViewClickedListener可以被设置

setOnItemViewClickedListener(new ItemViewClickedListener());

(在这种情况下)在onCreate的BrowseFragment。

关注微信公众号,定期为你推荐移动开发相关文章。


[译]SearchFragment --Android TV 开发手册十二_第6张图片
songwenju

你可能感兴趣的:([译]SearchFragment --Android TV 开发手册十二)