google leanback 库简介

“Leanback” 就是靠着看的意思。是指以放松的姿势倒在沙发上.谷歌推出 android.support.v17.leanback 软件包提供的 API 支持在电视设备上构建用户界面。它为电视应用提供了一些重要的小部件。这个库只支持到api 17以上的版本,也就是andorid 4.2,而一些效果也只是在api-21以上支持。

Demo 介绍

这是两个关于比较官方的Demo地址。有需要的可以下载

以下是Demo的部分截图


接下来就来说说代码结构
MVP的构建模式

Leanback 提供了model-view-presenter mvp的方式来构建应用。

  • model 是由应用开发者来提供,leanback对于model的实现没有加额外的限制,任何对象都是可以的。
  • view 还是由原来的android.view包下的类来实现。
  • Presenter 是基于现在的Adapter的该概念,并扩充为更具的灵活性和组合性。特别的是,绑定数据到view上的操作已经将adapter中分离出去,这部分逻辑由presenter去承担。

不信可以看看它的代码结构

至于MVP的好处这里就不用说了。

视图结构
  • 首先用android Tv的例子来介绍。运行程序时,整体内容被对齐在一个网格布局里。左侧的每一个标题header,都有右侧对应的一个内容行row,他们是一一对应的。header+content row由一个类 ListRow来表示。页面的整体其实是ListRow的集合

  • 整体是一个大的ArrayObjectAdapter 由一系列的ListRow来填充。view的呈现方式由ListRowPresenter来定义。
  • 一个ListRow 由HeaderItem 和一个小的ArrayObjectAdapter组成,这个一行中的ArrayObjectAdapter中放置我们定义的view,呈现方式由CardPresenter来定义。
    典型的代码如下:
List<Movie> list = MovieList.setupMovies();mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());CardPresenter cardPresenter = new CardPresenter();for (int i = 0; i < NUM_ROWS; i++) {if (i != 0) {Collections.shuffle(list);}ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);for (int j = 0; j < NUM_COLS; j++) {listRowAdapter.add(list.get(j % 5));}HeaderItem header = new HeaderItem(i, MovieList.MOVIE_CATEGORY[i]);mRowsAdapter.add(new ListRow(header, listRowAdapter));}setAdapter(mRowsAdapter);
  • 基本关系:
    ArrayObjectAdapter (RowsAdapter) ← A set of ListRow
    ListRow = HeaderItem + ArrayObjectAdapter (RowAdapter)
    ArrayObjectAdapter (RowAdapter) ← A set of Object (CardInfo/Item)

一些关键点

一版来说,谷歌的leanback 是(如上图)左边的菜单对应后面的一行。但是其实实际在开发中应用中,是左边的一个菜单对应右边一整个页面。第一种情况基本上上面已经说了。下面来说说第二种情况:

public class MainFragment extends BaseBrowseFragment {private static final String TAG = "MainFragment";private static final long HEADER_ID_DISCOVERY = 0;private static final long HEADER_ID_TV_SHOW = 1;private static final long HEADER_ID_FAV = 2;private static final long HEADER_ID_MEDIA = 3;private static final long HEADER_ID_SETTINGS = 4;  // 这些都是对应的左边菜单的id@Overrideprotected int getHeaderTitleArrayRes() {return R.array.main_header_title_array;}@Overrideprotected int getHeaderIconArrayRes() {return R.array.main_header_icon;}@Overrideprotected FragmentFactory getBrowseFragmentFactory() {return new PageRowFragmentFactory(mBackgroundManager);}protected void onEntranceTransitionEnd() {Log.d(TAG, "onEntranceTransitionEnd: ");}private static class PageRowFragmentFactory extends BrowseFragment.FragmentFactory {private final BackgroundManager mBackgroundManager;PageRowFragmentFactory(BackgroundManager backgroundManager) {this.mBackgroundManager = backgroundManager;}@Overridepublic Fragment createFragment(Object rowObj) {Row row = (Row) rowObj;long id = row.getHeaderItem().getId();         //每当点击后就会显示出对应的fragmentmBackgroundManager.setDrawable(null);if (id == HEADER_ID_TV_SHOW) {return new TvShowFragment();} else if (id == HEADER_ID_DISCOVERY) {return new DiscoveryFragment();} else if (id == HEADER_ID_MEDIA) {return new MediaFragment();}else if (id == HEADER_ID_FAV) {return new FavoriteFragment();}else if (id == HEADER_ID_SETTINGS) {return new SettingsFragment();}throw new IllegalArgumentException(String.format("Invalid row %s", rowObj));}}}

在leanback 中,右边页面显示的种类往往不同,例如,有视频列表,图片列表,音乐列表。那么这些在leanback中都是怎么处理的呢?其实在那些列表中的每一个item都是一个Card。然后其实就是在recycleview 中设置不同类型的item。

通过如下的selector 去选择不同的card

public class CardPresenterSelector extends PresenterSelector {private final Context mContext;private final HashMap<Card.Type, Presenter> presenters = new HashMap<Card.Type, Presenter>();public CardPresenterSelector(Context context) {mContext = context;}@Overridepublic Presenter getPresenter(Object item) {if (!(item instanceof Card)) throw new RuntimeException(String.format("The PresenterSelector only supports data items of type '%s'",Card.class.getName()));Card card = (Card) item;Presenter presenter = presenters.get(card.getCardType());if (presenter == null) {switch (card.getCardType()) {case SINGLE_LINE:presenter = new SingleLineCardPresenter(mContext);break;case VIDEO_GRID:presenter = new VideoCardViewPresenter(mContext, R.style.VideoGridCardTheme);break;case MOVIE:presenter = new CardPresenter();break;case MOVIE_COMPLETE:/*** {@link com.smartdevice.multimediaplayer.utils.Constants.ITEM_TYPE_MUSIC}* add for music which use in search and discovery model ,ordinal  =  0*/presenter = new MusicCardPresenter(mContext, false);break;case MUSIC_SMALL:presenter = new MusicCardPresenter(mContext, true);break;case MOVIE_BASE:case SQUARE_BIG:case ICON:presenter = new GridItemPresenter(mContext);break;case GRID_SQUARE:presenter = new GridItemPresenter(mContext);break;case MUSIC_ARTIST:presenter = new ArtistsCirclePresenter(mContext);break;case MUSIC_ALBUM:presenter = new AlbumCardPresenter(mContext);break;case CIRCLE_ICON:presenter = new CircleIconPresenter(mContext);break;case TV_SHOW_CURRENT:case TV_SHOW_UPCOMING:case TV_SHOW_RECOMMENDATION:case TV_SHOW_APP:case SPOTIFY_SEARCH:presenter = new TVShowPresenter(mContext);break;case POPULAR_MUSIC:presenter = new PopularMusicPresenter(mContext);break;case RECOMMEND_VIDEO:case CHILD_CHANNEL:presenter = new RecommendVideoPresenter(mContext);break;case FAVOITE_TVSHOW:presenter = new FavoriteTVShowPresenter(mContext);break;case DEVICE:presenter = new DeviceItemPresenter(mContext);break;case SETTINGS:presenter = new SettingsItemPresenter(mContext);break;case LOCALDEVICE:presenter = new LocalDeviceItemPresenter(mContext);break;case DLNA_DEVICE:presenter = new DlnaDeviceItemPresenter(mContext);break;case LOADING_ICON:presenter = new LoadingCardPresenter(false);break;case LOADING_ICON_ERROR:presenter = new LoadingCardPresenter(true);break;case YOUTUBE_VIDEO_ICON:presenter = new DiscoveryCardViewPresent(mContext);break;default:presenter = new ImageCardViewPresenter(mContext);break;}}presenters.put(card.getCardType(), presenter);return presenter;}

选择好card后,然后对应的card再去往里面填充数据,下面是一种card 类型。

public class MusicCardPresenter extends MusicAbstractCardPresenter<ImageCardView> {public static final String TAG = MusicCardPresenter.class.getSimpleName();public MusicCardPresenter(Context context, int cardThemeResId) {super(new ContextThemeWrapper(context, cardThemeResId));}public MusicCardPresenter(Context context, boolean isSmall) {this(context, isSmall ? R.style.MusicSmallCardStyle : R.style.MusicCardStyle);}@Overrideprotected ImageCardView onCreateView() {ImageCardView imageCardView = new ImageCardView(getContext());imageCardView.setFocusable(true);imageCardView.setFocusableInTouchMode(true);imageCardView.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP);return imageCardView;}@Overridepublic void onBindViewHolder(Card card, ImageCardView cardView) {cardView.setTitleText(card.getTitle());if (TextUtils.isEmpty(card.getFilePath())) {//spotify musicGlide.with(getContext()).load(card.getImageUrl()).into(cardView.getMainImageView());   这里使用Glide 框架来填充图片} else {//local music filesmImageFetcher.loadImage(card.getFilePath(), cardView.getMainImageView());}}@Overridepublic void onUnbindViewHolder(ImageCardView cardView) {super.onUnbindViewHolder(cardView);ImageWorker.cancelWork(cardView.getMainImageView());cardView.setBadgeImage(null);cardView.setMainImage(null);}
如何使用

build.gradle中导入

    implementation 'com.android.support:recyclerview-v7:27.1.0'implementation 'com.android.support:leanback-v17:27.1.0'   //主要是这个implementation 'com.android.support:recommendation:27.1.0'implementation 'com.android.support:preference-leanback-v17:27.1.0'

然后就可以正常调用了。

感谢:Android TV Leanback 简介

Android TV之谷歌android leanback框架详解相关推荐

  1. leanback android,Android TV之谷歌android leanback框架详解

    google leanback 库简介 "Leanback" 就是靠着看的意思.是指以放松的姿势倒在沙发上.谷歌推出 android.support.v17.leanback 软件 ...

  2. Android神匕首—Dagger2依赖注入框架详解

    简介 Dagger-匕首,鼎鼎大名的Square公司旗下又一把利刃(没错!还有一把黄油刀,唤作ButterKnife) Dagger2 是一个Android依赖注入框架,由谷歌开发,最早的版本Dagg ...

  3. Android 动画框架详解,第 1 部分

    2019独角兽企业重金招聘Python工程师标准>>> Android 平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果,本文将向读者阐述 Android 的动画框 ...

  4. Android 动画框架详解

    Android 动画框架详解 基本原理 朱 韦伟, 软件工程师, IBM 李 浩, 软件工程师, 爱格码 简介: Android 平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果.A ...

  5. Android 8.0学习(32)---Android 8.0源码目录结构详解

    Android 8.0源码目录结构详解 android的移植按如下流程:     (1)android linux 内核的普通驱动移植,让内核可以在目标平台上运行起来.     (2)正确挂载文件系统 ...

  6. Android消息传递之EventBus 3.0使用详解

    前言: 前面两篇不仅学习了子线程与UI主线程之间的通信方式,也学习了如何实现组件之间通信,基于前面的知识我们今天来分析一下EventBus是如何管理事件总线的,EventBus到底是不是最佳方案?学习 ...

  7. Android JNI使用方法,JNI机制详解

    Android JNI使用方法,JNI机制详解 JNI的出现使得开发者既可以利用Java语言跨平台.类库丰 富.开发便捷等特点,又可以利用Native语言的高效. JNI是JVM实现中的一部分,因此N ...

  8. Android 各大厂面试题汇总与详解(持续更新)

    介绍 目前网络中出现了好多各种面试题的汇总,有真实的也有虚假的,所以今年我将会汇总各大公司面试比较常见的问题,逐一进行解答.会一直集成,也会收集大家提供的面试题,如有错误,请大家指出,经过排查存在,会 ...

  9. Android进阶笔记:Messenger源码详解

    Messenger可以理解为一个是用于发送消息的一个类用法也很多,这里主要分析一下再跨进程的情况下Messenger的实现流程与源码分析.相信结合前面两篇关于aidl解析文章能够更好的对aidl有一个 ...

最新文章

  1. eclipse中解决/**/多行注释代码后,格式变乱的问题
  2. auto自动类型推断
  3. 关于VC网络编程中用 char 发送结构体的说明
  4. ehcache + mysql例子与性能测试
  5. Linux命令学习手册-tr命令 2015-07-26 20:35 9人阅读 评论(0) 收藏...
  6. show一下自己的文档编写功底
  7. Python之网络编程(socket基础)
  8. oracle 控制文件在哪里设置_oracle的controlfile控制文件
  9. 案例学习BlazeDS+Spring之十一:Simple Data Push
  10. vbs 获取计算机主机名,vbs 获取主机名
  11. 我在公司内部的分享(秒针系统)
  12. 批量 // 注释替换为 /*的注释
  13. 模集经典二级运放设计
  14. 基于STM32F103的电子磁密码锁智能门禁原理图PCB程序设计
  15. 超美二次元响应引导页源码
  16. 2019,我的影像记录
  17. python找零_Python 找零问题
  18. (3.6A)不用库函数实现字符串拼接
  19. 我的世界python写游戏_用python写游戏之 Give it up
  20. GateWay简介及使用

热门文章

  1. c语言基础学习11_项目实战:IDE(集成开发环境)
  2. 哪款中英翻译器简单实用?在线翻译的简单方法
  3. 那些命令可以查看 file1 文件的第 300-500 行的内容?
  4. 朴素贝叶斯 php,PHP实现机器学习之朴素贝叶斯算法详解.pdf
  5. windows下简单的音频采集示例
  6. mac装载移动硬盘失败
  7. SharePoint 2013 入门教程
  8. 外卖平台的设计与实现
  9. 龙芯1B:按键外部中断例程
  10. 关于okhttp3网络框架的onfailure错误