W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
編寫:awong1900 - 原文:http://developer.android.com/training/tv/discovery/searchable.html
Android TV使用Android搜索接口從安裝的應(yīng)用中檢索內(nèi)容數(shù)據(jù)并且釋放搜索結(jié)果給用戶。我們的應(yīng)用內(nèi)容數(shù)據(jù)能被包含在這些結(jié)果中,去給用戶即時(shí)訪問應(yīng)用程序中的內(nèi)容。
我們的應(yīng)用必須提供Android TV數(shù)據(jù)字段,它是用戶在搜索框中輸入字符生成的建議搜索結(jié)果。去做這個(gè),我們的應(yīng)用必須實(shí)現(xiàn)Content Provider,在searchable.xml配置文件描述content provider和其他必要的Android TV信息。我們也需要一個(gè)activity在用戶選擇一個(gè)建議的搜索結(jié)果時(shí)處理intent的觸發(fā)。所有的這些被描述在Adding Custom Suggestions。本文描述Android TV應(yīng)用搜索的關(guān)鍵點(diǎn)。
這節(jié)課展示Android中搜索的知識(shí),展示如何使我們的應(yīng)用在Android TV里是可被搜索的。確信我們熟悉Search API guide的解釋。在下面的這節(jié)課程之前,查看Adding Search Functionality訓(xùn)練課程。
這個(gè)討論描述的一些代碼,從Android Leanback示例代碼摘出。代碼可以在Github上找到。
SearchManager描述了數(shù)據(jù)字段,它被代表為SQLite數(shù)據(jù)庫的列。不管我們的數(shù)據(jù)格式,我們必須把我們的數(shù)據(jù)字段填到那些列,通常用存取我們的內(nèi)容數(shù)據(jù)的類。更多信息,查看Building a suggestion table()。
SearchManager類為AndroidTV包含了幾個(gè)列。下面是重要的一些列:
值 | 描述 |
---|---|
SUGGEST_COLUMN_TEXT_1 | 內(nèi)容名字 (必須) |
SUGGEST_COLUMN_TEXT_2 | 內(nèi)容的文本描述 |
SUGGEST_COLUMN_RESULT_CARD_IMAGE | 圖片/封面 |
SUGGEST_COLUMN_CONTENT_TYPE | 媒體的MIME類型 (必須) |
SUGGEST_COLUMN_VIDEO_WIDTH | 媒體的分辨率寬度 |
SUGGEST_COLUMN_VIDEO_HEIGHT | 媒體的分辨率高度 |
SUGGEST_COLUMN_PRODUCTION_YEAR | 內(nèi)容的產(chǎn)品年份 (必須) |
SUGGEST_COLUMN_DURATION | 媒體的時(shí)間長度 |
搜索framework需要以下的列:
當(dāng)這些內(nèi)容的列的值匹配Google服務(wù)的providers提供的的值時(shí),系統(tǒng)提供一個(gè)深鏈接到我們的應(yīng)用,用于詳情查看,以及指向應(yīng)用的其他Providers的鏈接。更多討論在在詳情頁顯示內(nèi)容。
我們的應(yīng)用的數(shù)據(jù)庫類可能定義以下的列:
public class VideoDatabase {
//The columns we'll include in the video database table
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;
public static final String KEY_AUDIO_CHANNEL_CONFIG =
SearchManager.SUGGEST_COLUMN_AUDIO_CHANNEL_CONFIG;
public static final String KEY_PURCHASE_PRICE = SearchManager.SUGGEST_COLUMN_PURCHASE_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;
...
當(dāng)我們創(chuàng)建從SearchManager列填充到我們的數(shù)據(jù)字段時(shí),我們也必須定義_ID去獲得每行的獨(dú)一無二的ID。
...
private static 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);
return map;
}
...
在上面的例子中,注意填充SUGGEST_COLUMN_INTENT_DATA_ID字段。這是URI的一部分,指向獨(dú)一無二的內(nèi)容到這一列的數(shù)據(jù),那是URI描述的內(nèi)容被存儲(chǔ)的最后部分。在URI的第一部分,與所有表格的列同樣,是設(shè)置在searchable.xml文件,用android:searchSuggestIntentData屬性。屬性被描述在Handle Search Suggestions。
如果URI的第一部分是不同于表格的每一列,我們填充SUGGEST_COLUMN_INTENT_DATA字段的值。當(dāng)用戶選擇這個(gè)內(nèi)容時(shí),這個(gè)intent被啟動(dòng)依據(jù)SUGGEST_COLUMN_INTENT_DATA_ID的混合intent數(shù)據(jù)或者android:searchSuggestIntentData
屬性和SUGGEST_COLUMN_INTENT_DATA字段值之一。
實(shí)現(xiàn)一個(gè)Content Provider去返回搜索術(shù)語建議到AndroidTV搜索框。系統(tǒng)需要我們的內(nèi)容容器提供建議,通過調(diào)用每次一個(gè)字母類型query())方法。在query())的實(shí)現(xiàn)中,我們的內(nèi)容容器搜索我們的建議數(shù)據(jù)并且返回一個(gè)光標(biāo)指向我們已經(jīng)指定的建議列。
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// Use the UriMatcher to see what kind of query we have and format the db query accordingly
switch (URI_MATCHER.match(uri)) {
case SEARCH_SUGGEST:
Log.d(TAG, "search suggest: " + selectionArgs[0] + " URI: " + uri);
if (selectionArgs == null) {
throw new IllegalArgumentException(
"selectionArgs must be provided for the Uri: " + uri);
}
return getSuggestions(selectionArgs[0]);
default:
throw new IllegalArgumentException("Unknown Uri: " + uri);
}
}
private Cursor 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
};
return mVideoDatabase.getWordMatch(query, columns);
}
...
在我們的manifest文件中,內(nèi)容容器接受特殊處理。相比被標(biāo)記為一個(gè)activity,它是被描述為[provider](http://developer.android.com/guide/topics/manifest/provider-element.html)。provider包括android:searchSuggestAuthority
屬性去告訴系統(tǒng)我們的內(nèi)容容器的名字空間。并且,我們必須設(shè)置它的android:exported
屬性為"true"
,這樣Android全局搜索能用它返回的搜索結(jié)果。
<provider android:name="com.example.android.tvleanback.VideoContentProvider"
android:authorities="com.example.android.tvleanback"
android:exported="true" />
我們的應(yīng)用必須包括res/xml/searchable.xml文件去配置搜索建議設(shè)置。它包括android:searchSuggestAuthority屬性去告訴系統(tǒng)內(nèi)容容器的名字空間。這必須匹配在AndroidManifest.xml
文件的[provider](http://developer.android.com/guide/topics/manifest/provider-element.html)元素的android:authorities 屬性的字符串值。
searchable.xml文件必須也包含在"android.intent.action.VIEW"
的android:searchSuggestIntentAction值去定義提供自定義建議的intent action。這與提供一個(gè)搜索術(shù)語的intent action不同,下面解釋。查看Declaring the intent action 用另一種方式去定義建議的intent action。
同intent action一起,我們的應(yīng)用必須提供我們定義的android:searchSuggestIntentData屬性的intent數(shù)據(jù)。這是指向內(nèi)容的URI的第一部分。它描述在填充的內(nèi)容表格中URI所有共同列的部分。URI的獨(dú)一無二的部分用 SUGGEST_COLUMN_INTENT_DATA_ID字段建立每一列,以上被描述在識(shí)別列。查看Declaring the intent data用另一種方式去定義建議的intent數(shù)據(jù)。
并且,注意android:searchSuggestSelection="?"
屬性為特定的值。這個(gè)值作為query())方法selection
參數(shù)。方法的問題標(biāo)記(?)值被代替為請求文本。
最后,我們也必須包含android:includeInGlobalSearch屬性值為"true"
。這是一個(gè)searchable.xml文件的例子:
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint"
android:searchSettingsDescription="@string/settings_description"
android:searchSuggestAuthority="com.example.android.tvleanback"
android:searchSuggestIntentAction="android.intent.action.VIEW"
android:searchSuggestIntentData="content://com.example.android.tvleanback/video_database_leanback"
android:searchSuggestSelection=" ?"
android:searchSuggestThreshold="1"
android:includeInGlobalSearch="true"
>
</searchable>
一旦搜索框有一個(gè)字匹配到了應(yīng)用列中的一個(gè)(被描述在上文的識(shí)別列),系統(tǒng)啟動(dòng)ACTION_SEARCH intent。我們應(yīng)用的activity處理intent搜索列的給定的字段資源,并且返回一個(gè)那些內(nèi)容項(xiàng)的列表。在我們的AndroidManifest.xml
文件中,我們指定的activity處理ACTION_SEARCH intent,像這樣:
...
<activity
android:name="com.example.android.tvleanback.DetailsActivity"
android:exported="true">
<!-- Receives the search request. -->
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<!-- No category needed, because the Intent will specify this class component -->
</intent-filter>
<!-- Points to searchable meta data. -->
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
...
<!-- Provides search suggestions for keywords against video meta data. -->
<provider android:name="com.example.android.tvleanback.VideoContentProvider"
android:authorities="com.example.android.tvleanback"
android:exported="true" />
...
activity必須參考searchable.xml文件描述可搜索的設(shè)置。用全局搜索框,manifest必須描述activity應(yīng)該收到的搜索請求。manifest必須描述[provider](http://developer.android.com/guide/topics/manifest/provider-element.html)元素,詳細(xì)被描述在searchable.xml文件。
如果我們有設(shè)置處理搜索建議描述的搜索配置和填充 SUGGEST_COLUMN_TEXT_1,SUGGEST_COLUMN_CONTENT_TYPE和SUGGEST_COLUMN_PRODUCTION_YEAR字段到識(shí)別列,一個(gè)深鏈接去查看詳情頁的內(nèi)容。當(dāng)用戶選擇一個(gè)搜索結(jié)果時(shí),詳情頁將打開。如圖1。
圖1 詳情頁顯示一個(gè)深鏈接為Google(Leanback)的視頻代碼。Sintel: ? copyright Blender Foundation, www.sintel.org.
當(dāng)用戶選擇我們的應(yīng)用鏈接,“Available On”
按鈕被標(biāo)識(shí)在詳情頁,系統(tǒng)啟動(dòng)activity處理ACTION_VIEW(在searchable.xml文件設(shè)置android:searchSuggestIntentAction值為"android.intent.action.VIEW"
)。
我們也能設(shè)置用戶intent去啟動(dòng)我們的activity,這個(gè)在在AndroidLeanback示例代碼應(yīng)用中演示。注意示例應(yīng)用啟動(dòng)它自己的LeanbackDetailsFragment
去顯示被選擇媒體的詳情,但是我們應(yīng)該啟動(dòng)activity去播放媒體。立即去保存用戶的另一次或兩次點(diǎn)擊。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: