Android Studio V3.12环境下TV开发教程(五)建立电视回放应用

Android Studio V3.12环境下TV开发教程

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

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

建立电视回放应用

浏览和播放媒体文件通常是电视应用程序提供的用户体验的一部分。 从零开始构建这样的体验,同时确保其快速,流畅和有吸引力可能是相当具有挑战性的。 无论您的应用是否提供对小型或大型媒体目录的访问,允许用户快速浏览选项并获取他们想要的内容非常重要。

Android框架提供了用于使用v17 leanback支持库为这些类型的应用程序构建用户界面的类。 这个库提供了一个类框架,用于创建一个高效且熟悉的界面,以最少的代码浏览和播放媒体文件。 这些课程旨在进行扩展和定制,以便您可以创建独特的应用体验。

本课程向您展示如何使用Leanback电视支持库构建浏览和播放媒体内容的电视应用程序。

主题

创建一个目录浏览器

了解如何使用Leanback支持库为媒体目录构建浏览界面。

提供卡片视图

了解如何使用Leanback支持库为内容项目构建卡片视图。

建立详细信息视图

了解如何使用Leanback支持库为媒体项目构建详细信息页面。

使用Leanback的运输控制

了解如何使用Leanback支持库为您的视频播放器构建传输控件。

显示一张现在玩的牌

了解如何使用MediaSession在主屏幕上显示正在使用的即时贴。

直接在表面上渲染视频

了解您的应用如何直接在主屏幕的表面上呈现预览视频。

添加引导步骤

了解如何使用Leanback支持库来指导用户完成一系列决策。

首次将用户引入您的应用

了解如何使用Leanback支持库向初次使用者展示如何充分利用您的应用程序。

启用后台播放

了解如何在用户点击主页时继续播放。

创建一个目录浏览器

运行在电视上的媒体应用程序需要允许用户浏览其内容产品,进行选择并开始播放内容。 这种类型的应用程序的内容浏览体验应该简单直观,并且在视觉上令人愉悦且引人入胜。

本课讨论如何使用v17 leanback支持库提供的类来实现用于从应用媒体目录中浏览音乐或视频的用户界面。

图1. Leanback示例应用程序浏览片段显示视频目录数据。

创建媒体浏览布局

leanback库中的BrowseFragment类允许您使用最少的代码创建用于浏览媒体项目类别和行的主要布局。 以下示例显示如何创建包含BrowseFragment对象的布局:

   

应用程序的主要活动设置此视图,如以下示例所示:

public class MainActivity extends Activity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);    }...

BrowseFragment方法使用视频数据和UI元素填充视图,并设置布局参数(如图标,标题以及是否启用类别标题)。

有关设置UI元素的更多信息,请参阅设置 UI元素。

有关隐藏标题的更多信息,请参阅隐藏或禁用标题。

实现BrowseFragment方法的应用程序的子类还为UI元素上的用户操作设置事件侦听器,并准备后台管理器,如以下示例所示:

public class MainFragment extends BrowseFragment implements        LoaderManager.LoaderCallbacks>> {...    @Override    public void onActivityCreated(Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        loadVideoData();        prepareBackgroundManager();        setupUIElements();        setupEventListeners();    }...    private void prepareBackgroundManager() {        mBackgroundManager = BackgroundManager.getInstance(getActivity());        mBackgroundManager.attach(getActivity().getWindow());        mDefaultBackground = getResources()            .getDrawable(R.drawable.default_background);        mMetrics = new DisplayMetrics();        getActivity().getWindowManager().getDefaultDisplay().getMetrics(mMetrics);    }    private void setupUIElements() {        setBadgeDrawable(getActivity().getResources()            .getDrawable(R.drawable.videos_by_google_banner));        // Badge, when set, takes precedent over title        setTitle(getString(R.string.browse_title));        setHeadersState(HEADERS_ENABLED);        setHeadersTransitionOnBackEnabled(true);        // set headers background color        setBrandColor(getResources().getColor(R.color.fastlane_background));        // set search icon color        setSearchAffordanceColor(getResources().getColor(R.color.search_opaque));    }    private void loadVideoData() {        VideoProvider.setContext(getActivity());        mVideosUrl = getActivity().getResources().getString(R.string.catalog_url);        getLoaderManager().initLoader(0, null, this);    }    private void setupEventListeners() {        setOnSearchClickedListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                Intent intent = new Intent(getActivity(), SearchActivity.class);                startActivity(intent);            }        });        setOnItemViewClickedListener(new ItemViewClickedListener());        setOnItemViewSelectedListener(new ItemViewSelectedListener());    }...

设置UI元素

在上面的示例中,私有方法setupUIElements()调用了几个BrowseFragment方法来设置媒体目录浏览器的样式:

setBadgeDrawable()将指定的可绘制资源放置在浏览片段的右上角,如图1和2所示。如果还调用了setTitle() ,则此方法将用可绘制资源替换标题字符串。 可绘制的资源应该是52dps高。

除非setBadgeDrawable() ,否则setBadgeDrawable()会在浏览片段的右上角设置标题字符串。

setHeadersState()setHeadersTransitionOnBackEnabled()隐藏或禁用标题。 有关更多信息,请参阅隐藏或禁用标题 。

setBrandColor()使用指定的颜色值为浏览片段中的UI元素(特别是标题部分背景颜色setBrandColor()设置背景颜色。

setSearchAffordanceColor()用指定的颜色值设置搜索图标的颜色。 搜索图标出现在浏览片段的左上角,如图1和2所示。

自定义标题视图

图1中显示的浏览片段列出了左侧窗格中的视频类别名称(行标题)。 文本视图显示视频数据库中的这些类别名称。 您可以自定义标题以在更复杂的布局中包含其他视图。 以下部分显示如何包含图像视图,该图像视图在类别名称旁边显示图标,如图2所示。

图2.浏览片段中的行标题,带有图标和文本标签。

行标题的布局定义如下:

       

使用Presenter并实现抽象方法来创建,绑定和取消绑定视图持有者。 以下示例显示如何使用两个视图(一个ImageView和一个TextView来绑定视图。

public class IconHeaderItemPresenter extends Presenter {    @Override    public ViewHolder onCreateViewHolder(ViewGroup viewGroup) {        LayoutInflater inflater = (LayoutInflater) viewGroup.getContext()                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);        View view = inflater.inflate(R.layout.icon_header_item, null);        return new ViewHolder(view);    }    @Override    public void onBindViewHolder(ViewHolder viewHolder, Object o) {        HeaderItem headerItem = ((ListRow) o).getHeaderItem();        View rootView = viewHolder.view;        ImageView iconView = (ImageView) rootView.findViewById(R.id.header_icon);        Drawable icon = rootView.getResources().getDrawable(R.drawable.ic_action_video, null);        iconView.setImageDrawable(icon);        TextView label = (TextView) rootView.findViewById(R.id.header_label);        label.setText(headerItem.getName());    }    @Override    public void onUnbindViewHolder(ViewHolder viewHolder) {    // no op    }}

你的头文件必须是可以调焦的,这样D-pad可以用来滚动它们。 有两种选择:

将你的视图设置为onBindViewHolder()焦点:

@Overridepublic void onBindViewHolder(ViewHolder viewHolder, Object o) {    HeaderItem headerItem = ((ListRow) o).getHeaderItem();    View rootView = viewHolder.view;    rootView.setFocusable(true) // Allows the D-Pad to navigate to this header item    //...}

将您的布​​局设置为可对焦:


   android:focusable="true">

最后,在显示目录浏览器的BrowseFragment实现中,使用setHeaderPresenterSelector()方法为行标题设置演示者,如以下示例所示。

setHeaderPresenterSelector(new PresenterSelector() {    @Override    public Presenter getPresenter(Object o) {        return new IconHeaderItemPresenter();    }});

有关完整示例,请参阅leanback示例中的IconHeaderItemPresenter。

隐藏或禁用标题

例如,有时您可能不希望行标题出现:当没有足够的类别需要可滚动列表时。 在片段的onActivityCreated()方法中调用BrowseFragment.setHeadersState()方法来隐藏或禁用行标题。 setHeadersState()方法将以下常量之一作为参数,设置浏览片段中标题的初始状态:

HEADERS_ENABLED - 创建浏览片段活动时,默认情况下会启用并显示标题。 标题的显示如图1和2所示。

HEADERS_HIDDEN - 创建浏览片段活动时,标题默认情况下处于启用和隐藏状态。 屏幕的标题部分已折叠,如提供卡片视图的 图1所示。 用户可以选择折叠页眉部分来展开它。

HEADERS_DISABLED - 创建浏览片段活动时,标题默认处于禁用状态,并且不会显示。

如果设置了HEADERS_ENABLEDHEADERS_HIDDEN则可以调用setHeadersTransitionOnBackEnabled()以支持从行中所选内容项移回行标题。 这是默认启用的(如果你不调用方法),但是如果你想自己处理后退运动,你应该将false值传递给setHeadersTransitionOnBackEnabled()并实现你自己的后端堆栈处理。

显示媒体列表

BrowseFragment类允许您使用适配器和演示BrowseFragment从媒体目录中定义和显示可浏览的媒体内容类别和媒体项目。 适配器使您能够连接到包含媒体目录信息的本地或联机数据源。 适配器使用演示者创建视图并将数据绑定到这些视图以在屏幕上显示项目。

以下示例代码显示了用于显示字符串数据的Presenter的实现:

public class StringPresenter extends Presenter {    private static final String TAG = "StringPresenter";    public ViewHolder onCreateViewHolder(ViewGroup parent) {        TextView textView = new TextView(parent.getContext());        textView.setFocusable(true);        textView.setFocusableInTouchMode(true);        textView.setBackground(                parent.getContext().getResources().getDrawable(R.drawable.text_bg));        return new ViewHolder(textView);    }    public void onBindViewHolder(ViewHolder viewHolder, Object item) {        ((TextView) viewHolder.view).setText(item.toString());    }    public void onUnbindViewHolder(ViewHolder viewHolder) {        // no op    }}

一旦为媒体项目构建了演示者类,就可以构建一个适配器并将其附加到BrowseFragment以在屏幕上显示这些项目以供用户浏览。 以下示例代码演示了如何使用前面的代码示例中显示的StringPresenter类构造适配器以显示这些类别中的类别和项目:

private ArrayObjectAdapter mRowsAdapter;private static final int NUM_ROWS = 4;@Overrideprotected void onCreate(Bundle savedInstanceState) {    ...    buildRowsAdapter();}private void buildRowsAdapter() {    mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());    for (int i = 0; i < NUM_ROWS; ++i) {        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(                new StringPresenter());        listRowAdapter.add("Media Item 1");        listRowAdapter.add("Media Item 2");        listRowAdapter.add("Media Item 3");        HeaderItem header = new HeaderItem(i, "Category " + i);        mRowsAdapter.add(new ListRow(header, listRowAdapter));    }    mBrowseFragment.setAdapter(mRowsAdapter);}

此示例显示适配器的静态实现。 典型的媒体浏览应用程序使用来自在线数据库或Web服务的数据。 有关使用从Web检索的数据的浏览应用程序的示例,请参阅Android Leanback示例应用程序 。

更新背景

为了在电视上为媒体浏览应用增加视觉趣味,您可以在用户浏览内容时更新背景图片。 这项技术可以使您的应用更具电影感和愉悦感。

Leanback支持库提供了一个BackgroundManager类,用于更改电视应用程序活动的背景。 以下示例显示如何创建一个简单方法来更新电视应用程序活动中的背景:

protected void updateBackground(Drawable drawable) {    BackgroundManager.getInstance(this).setDrawable(drawable);}

当用户浏览媒体列表时,许多现有的媒体浏览应用会自动更新背景。 为了做到这一点,您可以设置一个选择侦听器,根据用户的当前选择自动更新背景。 以下示例显示如何设置OnItemViewSelectedListener类来捕获选择事件并更新背景:

protected void clearBackground() {    BackgroundManager.getInstance(this).setDrawable(mDefaultBackground);}protected OnItemViewSelectedListener getDefaultItemViewSelectedListener() {    return new OnItemViewSelectedListener() {        @Override        public void onItemSelected(Object item, Row row) {            if (item instanceof Movie ) {                Drawable background = ((Movie)item).getBackdropDrawable();                updateBackground(background);            } else {                clearBackground();            }        }    };}

注意:上面的实现是一个简单的例子,用于说明。 在自己的应用程序中创建此功能时,应考虑在单独的线程中运行后台更新操作以获得更好的性能。 此外,如果您计划更新背景以响应用户滚动浏览项目,请考虑增加一段时间来延迟背景图片更新,直到用户安置一个项目。 这种技术避免了过多的背景图像更新。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,304评论 1 92
  • 教别人怎样阅读的书很多,《深阅读》是其中比较特别的一本。 这本书的作者,斋藤孝,毕业于东京大学法学部,并在该大学研...
    伍锌阅读 753评论 2 5
  • 经典心理测验到底适不适合用于企业用人的考察和筛选? 本文为作者的文章原稿,修改版已授权发表于微信公众号@智鼎人才官...
    EssieL阅读 1,436评论 0 2
  • 时光塌下,吹散了的一抹浮华终是随着落花悠悠落于相思树下,曾言过,你无畏金戈铁马,一把素琴,即已走遍天下。风终...
    尹夕颜阅读 112评论 0 1