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

leanback android,Android TV之谷歌android leanback框架详解googleleanback库简介“Leanback”就是靠着看的意思。是指以放松的姿势倒在沙发上.谷歌推出android.support.v17.leanback软件包提供的API支持在电视设备上构建用户界面。它为电视应用提供了一些重要的小部件。这个库只支持到api17以上的版本,也就是andorid4.2,而一些效果也只是在api-21以上支持。Demo介绍这是两个关于比较…

大家好,欢迎来到IT知识分享网。

google leanback 库简介

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

Demo 介绍

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

以下是Demo的部分截图

d33200aaa39bdf4057b9b48f96c0399e.png

612c3a7dccfab67eea5a9f6100a928d6.png

接下来就来说说代码结构

MVP的构建模式

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

model 是由应用开发者来提供,leanback对于model的实现没有加额外的限制,任何对象都是可以的。

view 还是由原来的android.view包下的类来实现。

Presenter 是基于现在的Adapter的该概念,并扩充为更具的灵活性和组合性。特别的是,绑定数据到view上的操作已经将adapter中分离出去,这部分逻辑由presenter去承担。

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

70b3a02e0fe14c94ae9ac269fa73f82c.png

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

视图结构

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

ade783c0ff142079d78fd00fa43d3522.png

整体是一个大的ArrayObjectAdapter 由一系列的ListRow来填充。view的呈现方式由ListRowPresenter来定义。

一个ListRow 由HeaderItem 和一个小的ArrayObjectAdapter组成,这个一行中的ArrayObjectAdapter中放置我们定义的view,呈现方式由CardPresenter来定义。

典型的代码如下:

List 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)

948b7be10852715bfd0c7d9fc9e80283.png

一些关键点

一版来说,谷歌的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

@Override

protected int getHeaderTitleArrayRes() {

return R.array.main_header_title_array;

}

@Override

protected int getHeaderIconArrayRes() {

return R.array.main_header_icon;

}

@Override

protected 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;

}

@Override

public Fragment createFragment(Object rowObj) {

Row row = (Row) rowObj;

long id = row.getHeaderItem().getId(); //每当点击后就会显示出对应的fragment

mBackgroundManager.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 presenters = new HashMap();

public CardPresenterSelector(Context context) {

mContext = context;

}

@Override

public 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 {

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);

}

@Override

protected ImageCardView onCreateView() {

ImageCardView imageCardView = new ImageCardView(getContext());

imageCardView.setFocusable(true);

imageCardView.setFocusableInTouchMode(true);

imageCardView.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP);

return imageCardView;

}

@Override

public void onBindViewHolder(Card card, ImageCardView cardView) {

cardView.setTitleText(card.getTitle());

if (TextUtils.isEmpty(card.getFilePath())) {//spotify music

Glide.with(getContext())

.load(card.getImageUrl())

.into(cardView.getMainImageView()); 这里使用Glide 框架来填充图片

} else {//local music files

mImageFetcher.loadImage(card.getFilePath(), cardView.getMainImageView());

}

}

@Override

public 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 简介

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/9788.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信