Android Studio TV开发教程(十六)让电视应用程序可搜索

Android Studio TV开发教程

(转自Android官网https://developer.android.com/training/tv/start)

文章源自:光谷佳武 https://blog.csdn.net/jiawuhan/article/details/80647943


让电视应用程序可搜索

Android TV使用Android 搜索界面从已安装的应用中检索内容数据并将搜索结果提供给用户。 这些结果可以包含您应用的内容数据,以便用户即时访问您应用中的内容。

当用户在搜索对话框中输入字符时,您的应用必须向Android TV提供数据字段,从中生成建议的搜索结果。 要做到这一点,您的应用必须实施一个内容提供商 ,提供建议以及一个searchable.xml描述内容提供商和Android TV其他重要信息的searchable.xml配置文件。 您还需要一个处理用户选择建议的搜索结果时触发的意图的活动。 所有这些在添加自定义建议中都有更详细的描述。 这里描述了Android TV应用程序的要点。

本课程基于您在Android中使用搜索的知识,向您展示如何让您的应用在Android TV中搜索。 在学习本课之前,请确保您熟悉“ 搜索API”指南中介绍的概念。 另请参阅培训添加搜索功能 

本讨论描述了Android Leanback示例应用程序中的一些代码,可在GitHub上找到。

注意: Android TV的搜索界面还会检索Google搜索服务器中已标记为与Google Watch操作配合使用的内容。   如果您通过观看动作标记将内容添加到Google的搜索索引中,则您的内容将显示在带有用户界面的Android TV搜索结果中,用户可以使用该界面开始查看应用中的内容。   有关观看动作的更多信息,请参阅电视和电影 ,并申请观看动作节目 

识别列

SearchManager通过将它们表示为本地数据库的列来描述它所期望的数据字段。 无论您的数据格式如何,您都必须将数据字段映射到这些列,通常位于访问您的内容数据的类中。 有关构建将现有数据映射到必填字段的类的信息,请参阅构建建议表 

SearchManager类包含Android TV的多个列。 下面介绍一些更重要的栏目。

描述
SUGGEST_COLUMN_TEXT_1 您的内容的名称(必填)
SUGGEST_COLUMN_TEXT_2 您的内容的文字说明
SUGGEST_COLUMN_RESULT_CARD_IMAGE 您的内容的图像/海报/封面
SUGGEST_COLUMN_CONTENT_TYPE 媒体的MIME类型(必填)
SUGGEST_COLUMN_VIDEO_WIDTH 媒体的分辨率宽度
SUGGEST_COLUMN_VIDEO_HEIGHT 您媒体的分辨率高度
SUGGEST_COLUMN_PRODUCTION_YEAR 您的内容的生产年份(必填)
SUGGEST_COLUMN_DURATION 媒体的持续时间(以毫秒为单位)(必需)

搜索框架需要以下列:

  • SUGGEST_COLUMN_TEXT_1
  • SUGGEST_COLUMN_CONTENT_TYPE
  • SUGGEST_COLUMN_PRODUCTION_YEAR
  • SUGGEST_COLUMN_DURATION

当您的内容的这些列的值与Google服务器找到的其他提供商的相同内容的值匹配时,系统会在内容的详细信息视图中为您的应用提供深层链接 ,并提供指向其他提供商的应用的链接。 在下面详细信息屏幕中的显示内容中对此进行了更多的讨论。

你的应用程序的数据库类可能如下定义列:

公共类VideoDatabase {
   //我们将包含在视频数据库表中的列
   public static final String KEY_NAME = SearchManager.SUGGEST_COLUMN_TEXT_1;
   public static final String KEY_DESCRIPTION = SearchManager.SUGGEST_COLUMN_TEXT_2;
   public static final String KEY_ICON = SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE;
   public static final String KEY_DATA_TYPE = SearchManager.SUGGEST_COLUMN_CONTENT_TYPE;
   public static final String KEY_IS_LIVE = SearchManager.SUGGEST_COLUMN_IS_LIVE;
   public static final String KEY_VIDEO_WIDTH = SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH;
   public static final String KEY_VIDEO_HEIGHT = SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT;
  公共静态最终字符串KEY_AUDIO_CHANNEL_CONFIG =
           SearchManager.SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG;
   public static final String KEY_PURCHASE_PRICE = SearchManager.SUGGEST_COLUMN_PUR​​CHASE_PRICE;
   public static final String KEY_RENTAL_PRICE = SearchManager.SUGGEST_COLUMN_RENTAL_PRICE;
   public static final String KEY_RATING_STYLE = SearchManager.SUGGEST_COLUMN_RATING_STYLE;
   public static final String KEY_RATING_SCORE = SearchManager.SUGGEST_COLUMN_RATING_SCORE;
   public static final String KEY_PRODUCTION_YEAR = SearchManager.SUGGEST_COLUMN_PRODUCTION_YEAR;
   public static final String KEY_COLUMN_DURATION = SearchManager.SUGGEST_COLUMN_DURATION;
   public static final String KEY_ACTION = SearchManager.SUGGEST_COLUMN_INTENT_ACTION;
 ...

当您将SearchManager列映射到数据字段时,还必须指定_ID以赋予每行唯一的ID。

 ...
  私有静态HashMap  buildColumnMap(){
     HashMap  map = new HashMap ();
     map.put(KEY_NAME,KEY_NAME);
     map.put(KEY_DESCRIPTION,KEY_DESCRIPTION);
     map.put(KEY_ICON,KEY_ICON);
     map.put(KEY_DATA_TYPE,KEY_DATA_TYPE);
     map.put(KEY_IS_LIVE,KEY_IS_LIVE);
     map.put(KEY_VIDEO_WIDTH,KEY_VIDEO_WIDTH);
     map.put(KEY_VIDEO_HEIGHT,KEY_VIDEO_HEIGHT);
     map.put(KEY_AUDIO_CHANNEL_CONFIG,KEY_AUDIO_CHANNEL_CONFIG);
     map.put(KEY_PURCHASE_PRICE,KEY_PURCHASE_PRICE);
     map.put(KEY_RENTAL_PRICE,KEY_RENTAL_PRICE);
     map.put(KEY_RATING_STYLE,KEY_RATING_STYLE);
     map.put(KEY_RATING_SCORE,KEY_RATING_SCORE);
     map.put(KEY_PRODUCTION_YEAR,KEY_PRODUCTION_YEAR);
     map.put(KEY_COLUMN_DURATION,KEY_COLUMN_DURATION);
     map.put(KEY_ACTION,KEY_ACTION);
     map.put(BaseColumns._ID,“rowid AS”+
             BaseColumns._ID);
     map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID,“rowid AS”+
             SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
     map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID,“rowid AS”+
             SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
    返回地图;
   }
 ...

在上面的示例中,请注意映射到SUGGEST_COLUMN_INTENT_DATA_ID字段。 这是指向此行中数据唯一的内容的URI部分 - 即描述内容存储位置的URI的最后部分。 URI的第一部分(当它与表中的所有行通用时)在searchable.xml文件中设置为android:searchSuggestIntentData属性,如下面的处理搜索建议中所述。

如果URI的第一部分对于表中的每一行都不相同,则可以使用SUGGEST_COLUMN_INTENT_DATA字段映射该值。 当用户选择此内容时,触发的意图将从SUGGEST_COLUMN_INTENT_DATA_IDandroid:searchSuggestIntentData属性或SUGGEST_COLUMN_INTENT_DATA字段值的组合中提供意图数据。

提供搜索建议数据

实施内容提供商 ,将搜索字词建议返回到Android TV搜索对话框。 每次输入一个字母时,系统都会通过调用query()方法来查询您的内容提供者的建议。 在实现query() ,您的内容提供者将搜索您的建议数据并返回一个指向您指定的建议行的Cursor 

 @覆盖
  公共游标查询(Uri uri,String []投影,字符串选择,String [] selectionArgs,
                       String sortOrder){
     //使用UriMatcher查看我们拥有哪种查询并相应地格式化数据库查询
    开关(URI_MATCHER.match(uri)){
      案例SEARCH_SUGGEST:
           Log.d(TAG,“search suggest:”+ selectionArgs [0] +“URI:”+ uri);
           if(selectionArgs == null){
              抛出新的IllegalArgumentException(
                       “必须为Uri提供selectionArgs:”+ uri);
           }
          返回getSuggestions(selectionArgs [0]);
      默认:
          抛出新的IllegalArgumentException(“未知的Uri:”+ uri);
     }
   }

  私人游标getSuggestions(String query){
     query = query.toLowerCase();
     String [] columns = new String [] {
       BaseColumns._ID,
       VideoDatabase.KEY_NAME,
       VideoDatabase.KEY_DESCRIPTION,
       VideoDatabase.KEY_ICON,
       VideoDatabase.KEY_DATA_TYPE,
       VideoDatabase.KEY_IS_LIVE,
       VideoDatabase.KEY_VIDEO_WIDTH,
       VideoDatabase.KEY_VIDEO_HEIGHT,
       VideoDatabase.KEY_AUDIO_CHANNEL_CONFIG,
       VideoDatabase.KEY_PURCHASE_PRICE,
       VideoDatabase.KEY_RENTAL_PRICE,
       VideoDatabase.KEY_RATING_STYLE,
       VideoDatabase.KEY_RATING_SCORE,
       VideoDatabase.KEY_PRODUCTION_YEAR,
       VideoDatabase.KEY_COLUMN_DURATION,
       VideoDatabase.KEY_ACTION,
       SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID
     };
    返回mVideoDatabase.getWordMatch(查询,列);
   }
 ...

在您的清单文件中,内容提供者会受到特殊待遇。 它不是被标记为活动,而是被描述为一个  该提供程序包含android:searchSuggestAuthority属性,以告知系统您的内容提供者的名称空间。 此外,您必须将其android:exported属性设置为"true"以便Android全局搜索可以使用从其返回的结果。

 
    机器人:当局= “com.example.android.tvleanback”
     android:exported =“true”/>

处理搜索建议

您的应用必须包含res/xml/searchable.xml文件才能配置搜索建议设置。 它包含android:searchSuggestAuthority属性,以告知系统内容提供者的名称空间。 这必须与您在AndroidManifest.xml文件中元素的android:authorities属性中指定的字符串值匹配。

您的应用必须包含一个标签 ,即应用的名称。 枚举可搜索的应用程序时,系统搜索设置使用此标签。

searchable.xml文件还必须包含值为"android.intent.action.VIEW"android:searchSuggestIntentAction ,以定义提供自定义建议的意图操作。 这与提供搜索字词的意图操作不同,下面将对此进行解释。 另请参阅为其他方式声明意向操作以声明意向操作以获取建议。

除了意图操作之外,您的应用必须提供您使用android:searchSuggestIntentData属性指定的意图数据。 这是指向内容的URI的第一部分。 它描述了该内容映射表中所有行共有的URI部分。 如上面的标识列中所述,每行唯一的URI部分使用SUGGEST_COLUMN_INTENT_DATA_ID字段建立。 另请参阅声明意向数据以用于声明意向数据以获得建议的其他方式。

另外,请注意android:searchSuggestSelection=" ?" 属性,它指定作为query()方法的selection参数传递的值,其中问号( ? )值被替换为查询文本。

最后,还必须包含值为"true"android:includeInGlobalSearch属性。 这是一个示例searchable.xml文件:

 
    机器人:标签= “@字符串/ search_label”
    机器人:提示= “@字符串/ search_hint”
    机器人:searchSettingsDescription = “@字符串/ settings_description”
    机器人:searchSuggestAuthority = “com.example.android.tvleanback”
    机器人:searchSuggestIntentAction = “android.intent.action.VIEW”
    机器人:searchSuggestIntentData = “内容://com.example.android.tvleanback/video_database_leanback”
     android:searchSuggestSelection =“?”
    机器人:searchSuggestThreshold = “1”
    机器人:includeInGlobalSearch = “真”>
 

处理搜索条件

只要搜索对话框中有一个词与您应用的某个列中的值相匹配(在上面的标识列中进行了描述),系统就会触发ACTION_SEARCH意图。 处理该意图的应用程序中的活动会搜索存储库中的列,其中包含值的给定单词,并返回包含这些列的内容项列表。 在您的AndroidManifest.xml文件中,您指定处理ACTION_SEARCH意图的活动,如下所示:

 ...
   <活动
      机器人:名字= “com.example.android.tvleanback.DetailsActivity”
      机器人:导出=“真”>

       <! - 接收搜索请求。  - >
       <意图滤波器>
           
           <! - 不需要类别,因为Intent会指定这个类组件 - >
       

       <! - 指向可搜索的元数据。  - >
       
           android:resource =“@ xml / searchable”/>
   
 ...
   <! - 针对视频元数据提供针对关键字的搜索建议。  - >
   
      机器人:当局= “com.example.android.tvleanback”
       android:exported =“true”/>
 ...

该活动还必须通过引用searchable.xml文件来描述可搜索的配置。 要使用全局搜索对话框 ,清单必须描述哪些活动应该接收搜索查询。 清单还必须描述元素,完全如在searchable.xml文件中所述。

在详细信息屏幕中深入链接到您的应用

如果您按照处理搜索建议中所述设置了搜索配置,并SUGGEST_COLUMN_PRODUCTION_YEAR 识别列中所述映射了SUGGEST_COLUMN_TEXT_1  SUGGEST_COLUMN_CONTENT_TYPESUGGEST_COLUMN_PRODUCTION_YEAR字段,则在您的内容的深层链接出现在用户内容的监视操作选择一个搜索结果,如图1所示。

图1.详细信息屏幕显示Google视频(Leanback)示例应用程序的深层链接。 Sintel:©版权所有Blender基金会,www.sintel.org。

当用户选择细节屏幕上的“Available On”按钮确定的应用程序链接时,系统会启动处理ACTION_VIEW (设置为android:searchSuggestIntentAction ,值为"android.intent.action.VIEW"searchable.xml文件中)。

您还可以设置自定义意图来启动您的活动,并在Android Leanback示例应用程序中对此进行了演示。 请注意,示例应用程序启动了自己的LeanbackDetailsFragment以显示所选媒体的详细信息,但您应该立即启动播放媒体的活动,以另外单击一两个用户来保存该用户。

搜索行为

Android TV可以从主屏幕和应用内部搜索。 这两种情况的搜索结果不同。

从主屏幕搜索

当您从主屏幕搜索时,第一个结果出现在实体卡片中。 如果有应用可以播放内容,则每张卡片的链接都会显示在卡片的底部。

您无法以编程方式将应用程序放入实体卡。 为了成为回放选项,应用的搜索结果必须与内容的标题,年份和持续时间相匹配。 例如, leanback-assistant示例应用程序会返回“Big Buck Bunny”的结果,其中包含用于查看电影的Leanback-assistant选项。

该卡下方可能有更多搜索结果。 要看到它们,用户必须按下遥控器并向下滚动。 每个应用程序的结果都显示在单独的行中。 您无法控制行排序。 首先列出支持监视操作的应用程序。

从你的应用搜索

用户可以通过从远程或游戏手柄控制器启动麦克风,从您的应用程序开始搜索。 搜索结果显示在应用内容的顶部。 您的应用使用其自己的全球搜索提供商生成搜索结果。

学到更多

要详细了解搜索电视应用,请阅读搜索概述和添加搜索功能 

有关如何使用SearchFragment自定义应用内搜索体验的更多信息,请阅读电视应用内的搜索 

您还可以查看Android Leanback和Leanback-assistant示例应用程序。


你可能感兴趣的:(佳武AndroidTV教程)