کارت رسانه یک ViewGroup مستقل است که ابرداده رسانه مانند عنوان، آلبوم هنری و موارد دیگر را نمایش میدهد و کنترلهای پخش سطحی مانند پخش و مکث ، پرش و حتی اقدامات سفارشی ارائه شده توسط برنامه رسانه شخص ثالث را نمایش میدهد. یک کارت رسانه همچنین میتواند صفی از آیتمهای رسانه مانند فهرست پخش را نشان دهد.
شکل 1. اجرای نمونه کارت رسانه.
کارت های رسانه ای چگونه در AAOS پیاده سازی می شوند؟
ViewGroup هایی که اطلاعات رسانه را نشان می دهند، به روز رسانی های LiveData را از مدل داده های کتابخانه car-media-common
، PlaybackViewModel
، مشاهده می کنند تا ViewGroup را پر کنند. هر بهروزرسانی LiveData مربوط به زیرمجموعهای از اطلاعات رسانهای است که تغییر کرده است، مانند MediaItemMetadata
، PlaybackStateWrapper
، و MediaSource
.
از آنجایی که این رویکرد منجر به کدهای مکرر می شود (هر برنامه مشتری روی هر قسمت از LiveData Observers اضافه می کند و به بسیاری از View های مشابه داده های به روز شده اختصاص داده می شود)، ما PlaybackCardController
را ایجاد کردیم.
PlaybackCardController
PlaybackCardController
به کتابخانه car-media-common
اضافه شده است تا به ایجاد کارت رسانه کمک کند. این یک کلاس عمومی است که با یک ViewGroup ( mView
)، PlaybackViewModel ( mDataModel
)، PlaybackCardViewModel ( mViewModel
) و نمونه MediaItemsRepository
( mItemsRepository
) ساخته شده است.
در تابع setupController
، ViewGroup برای نماهای خاص با ID، با mView.findViewById(R.id.xxx)
تجزیه می شود و به اشیاء View محافظت شده اختصاص داده می شود.
private void getViewsFromWidget() {
mTitle = mView.findViewById(R.id.title);
mAlbumCover = mView.findViewById(R.id.album_art);
mDescription = mView.findViewById(R.id.album_title);
mLogo = mView.findViewById(R.id.content_format);
mAppIcon = mView.findViewById(R.id.media_widget_app_icon);
mAppName = mView.findViewById(R.id.media_widget_app_name);
// ...
}
هر بهروزرسانی LiveData از PlaybackViewModel
در یک روش محافظت شده مشاهده میشود و با Views مربوط به دادههای دریافتی تعامل دارد. به عنوان مثال، یک ناظر در MediaItemMetadata
عنوان را روی mTitle
TextView
تنظیم می کند و MediaItemMetadata.ArtworkRef
را به آلبوم هنری ImageBinder
mAlbumArtBinder
ارسال می کند. اگر ابرداده خالی باشد، View ها پنهان می شوند. در صورت لزوم، زیر کلاس های Controller می توانند این منطق را لغو کنند.
mDataModel.getMetadata().observe(mViewLifecycle, this::updateMetadata);
// ...
/** Update views with {@link MediaItemMetadata} */
protected void updateMetadata(MediaItemMetadata metadata) {
if (metadata != null) {
String defaultTitle = mView.getContext().getString(
R.string.metadata_default_title);
updateTextViewAndVisibility(mTitle, metadata.getTitle(), defaultTitle);
updateTextViewAndVisibility(mSubtitle, metadata.getSubtitle());
updateMediaLink(mSubtitleLinker,metadata.getSubtitleLinkMediaId());
updateTextViewAndVisibility(mDescription, metadata.getDescription());
updateMediaLink(mDescriptionLinker, metadata.getDescriptionLinkMediaId());
updateMetadataAlbumCoverArtworkRef(metadata.getArtworkKey());
updateMetadataLogoWithUri(metadata);
} else {
ViewUtils.setVisible(mTitle, false);
ViewUtils.setVisible(mSubtitle, false);
ViewUtils.setVisible(mAlbumCover, false);
ViewUtils.setVisible(mDescription, false);
ViewUtils.setVisible(mLogo, false);
}
}
PlaybackCardController را گسترش دهید
برنامههای سرویس گیرندهای که میخواهند یک کارت رسانه ایجاد کنند، باید PlaybackCardController
را در صورتی که توانایی بیشتری دارند در هر بهروزرسانی LiveData انجام دهند، گسترش دهند. مشتریان موجود در AAOS از این الگو پیروی می کنند. ابتدا باید یک زیر کلاس PlaybackCardController
مانند MediaCardController
ایجاد شود. بعد، MediaCardController
باید یک کلاس Builder داخلی استاتیک اضافه کند که کلاس PlaybackCardController
را گسترش دهد.
public class MediaCardController extends PlaybackCardController {
// extra fields specific to MediaCardController
/** Builder for {@link MediaCardController}. Overrides build() method to
* return NowPlayingController rather than base {@link PlaybackCardController}
*/
public static class Builder extends PlaybackCardController.Builder {
@Override
public MediaCardController build() {
MediaCardController controller = new MediaCardController(this);
controller.setupController();
return controller;
}
}
public MediaCardController(Builder builder) {
super(builder);
// any other function calls needed in constructor
// ...
}
}
PlaybackCardController یا یک کلاس فرعی را نمونه سازی کنید
کلاس Controller باید از یک Fragment یا Activity نمونه برداری شود تا یک LifecycleOwner برای ناظران LiveData داشته باشد.
mMediaCardController = (MediaCardController) new MediaCardController.Builder()
.setModels(mViewModel.getPlaybackViewModel(),
mViewModel,
mViewModel.getMediaItemsRepository())
.setViewGroup((ViewGroup) view)
.build();
mViewModel
یک نمونه از PlaybackCardViewModel
(یا زیر کلاس) است.
PlaybackCardViewModel برای ذخیره وضعیت
PlaybackCardViewModel
یک ViewModel ذخیرهکننده حالت است که به یک Fragment یا Activity گره خورده است که باید برای بازسازی محتویات کارت رسانه در صورت ایجاد تغییر پیکربندی استفاده شود (مانند تغییر از تم روشن به تاریک هنگامی که کاربر از طریق یک تونل رانندگی میکند). PlaybackCardViewModel
پیشفرض ذخیرهسازی نمونههای MediaModel
را برای بازپخش انجام میدهد، که PlaybackViewModel
و MediaItemsRepository
را میتوان از آنها بازیابی کرد. از PlaybackCardViewModel
برای ردیابی وضعیت صف، تاریخچه و منوی سرریز از طریق گیرنده ها و تنظیم کننده های ارائه شده استفاده کنید.
public class PlaybackCardViewModel extends AndroidViewModel {
private MediaModels mModels;
private boolean mNeedsInitialization = true;
private boolean mQueueVisible = false;
private boolean mHistoryVisible = false;
private boolean mOverflowExpanded = false;
public PlaybackCardViewModel(@NonNull Application application) {
super(application);
}
/** Initialize the PlaybackCardViewModel */
public void init(MediaModels models) {
mModels = models;
mNeedsInitialization = false;
}
/**
* Returns whether the ViewModel needs to be initialized. The ViewModel may
* need re-initialization if a config change occurs or if the system kills
* the Fragment.
*/
public boolean needsInitialization() {
return mNeedsInitialization;
}
public MediaItemsRepository getMediaItemsRepository() {
return mModels.getMediaItemsRepository();
}
public PlaybackViewModel getPlaybackViewModel() {
return mModels.getPlaybackViewModel();
}
public MediaSourceViewModel getMediaSourceViewModel() {
return mModels.getMediaSourceViewModel();
}
public void setQueueVisible(boolean visible) {
mQueueVisible = visible;
}
public boolean getQueueVisible() {
return mQueueVisible;
}
public void setHistoryVisible(boolean visible) {
mHistoryVisible = visible;
}
public boolean getHistoryVisible() {
return mHistoryVisible;
}
public void setOverflowExpanded(boolean expanded) {
mOverflowExpanded = expanded;
}
public boolean getOverflowExpanded() {
return mOverflowExpanded;
}
}
در صورت نیاز به ردیابی وضعیت های اضافی، این کلاس می تواند تمدید شود.
نمایش یک صف در کارت رسانه
PlaybackViewModel
API های LiveData را برای تشخیص اینکه آیا MediaSource از یک صف پشتیبانی می کند و برای بازیابی لیست اشیاء MediaItemMetadata
در صف ارائه می دهد. اگرچه این APIها می توانند مستقیماً برای پر کردن یک شی RecyclerView
با اطلاعات صف مورد استفاده قرار گیرند، یک کلاس PlaybackQueueController
به کتابخانه car-media-common
اضافه شده است تا این فرآیند را ساده کند. طرح بندی برای هر آیتم در CarUiRecyclerView
توسط برنامه مشتری و همچنین یک طرح سرصفحه اختیاری مشخص شده است. برنامه مشتری همچنین می تواند تعداد موارد نشان داده شده در صف را در طول وضعیت درایو با محدودیت های UXR سفارشی محدود کند.
سازنده و تنظیم کننده PlaybackQueueController
در نمونه زیر نشان داده شده است. منابع طرحبندی queueResource
و headerResource
را میتوان بهعنوان Resources.ID_NULL
ارسال کرد، اگر در مورد اول، کانتینر قبلاً حاوی CarUiRecyclerView
با id queue_list
باشد و در مورد دوم، صف دارای سرصفحه نباشد.
/**
* Construct a PlaybackQueueController. If clients don't have a separate
* layout for the queue, where the queue is already inflated within the
* container, they should pass {@link Resources.ID_NULL} as the LayoutRes
* resource. If clients don't require a UxrContentLimiter, they should pass
* null for uxrContentLimiter and the int passed for uxrConfigurationId will
* be ignored.
*/
public PlaybackQueueController(
ViewGroup container,
@LayoutRes int queueResource,
@LayoutRes int queueItemResource,
@LayoutRes int headerResource,
LifecycleOwner lifecycleOwner,
PlaybackViewModel playbackViewModel,
MediaItemsRepository itemsRepository,
@Nullable LifeCycleObserverUxrContentLimiter uxrContentLimiter,
int uxrConfigurationId) {
// ...
}
public void setShowTimeForActiveQueueItem(boolean show) {
mShowTimeForActiveQueueItem = show;
}
public void setShowIconForActiveQueueItem(boolean show) {
mShowIconForActiveQueueItem = show;
}
public void setShowThumbnailForQueueItem(boolean show) {
mShowThumbnailForQueueItem = show;
}
public void setShowSubtitleForQueueItem(boolean show) {
mShowSubtitleForQueueItem = show;
}
/** Calls {@link RecyclerView#setVerticalFadingEdgeEnabled(boolean)} */
public void setVerticalFadingEdgeLengthEnabled(boolean enabled) {
mQueue.setVerticalFadingEdgeEnabled(enabled);
}
public void setCallback(PlaybackQueueCallback callback) {
mPlaybackQueueCallback = callback;
}
طرحبندی هر آیتم صف باید حاوی شناسههایی برای Viewهایی باشد که میخواهد نشان دهد که مطابق با موارد استفاده شده در کلاس داخلی QueueViewHolder
است.
QueueViewHolder(View itemView) {
super(itemView);
mView = itemView;
mThumbnailContainer = itemView.findViewById(R.id.thumbnail_container);
mThumbnail = itemView.findViewById(R.id.thumbnail);
mSpacer = itemView.findViewById(R.id.spacer);
mTitle = itemView.findViewById(R.id.queue_list_item_title);
mSubtitle = itemView.findViewById(R.id.queue_list_item_subtitle);
mCurrentTime = itemView.findViewById(R.id.current_time);
mMaxTime = itemView.findViewById(R.id.max_time);
mTimeSeparator = itemView.findViewById(R.id.separator);
mActiveIcon = itemView.findViewById(R.id.now_playing_icon);
// ...
}
برای نمایش یک صف در کارت رسانه ای که با PlaybackCardController
(یا یک زیر کلاس) ایجاد شده است، PlaybackQueueController
را می توان در سازنده PlaybackCardController
با استفاده از mDataModel
و mItemsRepository
برای نمونه های PlaybackViewModel
و MediaItemsRepository
به ترتیب ساخت.
نمایش تاریخچه رسانههایی که قبلاً پخش شدهاند
در این بخش، نحوه نمایش و نمایش تاریخچه منابع رسانهای که قبلاً پخش شدهاند را میآموزید.
لیست تاریخچه را با PlaybackCardViewModel API دریافت کنید
PlaybackCardViewModel
یک API LiveData به نام getHistoryList()
برای بازیابی لیست سابقه رسانه ارائه می دهد. یک LiveData حاوی لیستی از منابع رسانه ای که قبلاً پخش شده اند را برمی گرداند. از این داده ها می توان برای پر کردن یک شی CarUiRecyclerView
استفاده کرد. مشابه PlaybackQueueController
، کلاسی به نام PlaybackHistoryController
به کتابخانه car-media-common
اضافه شده است تا فرآیند را ساده کند.
public class PlaybackCardViewModel extends AndroidViewModel {
public PlaybackCardViewModel(@NonNull Application application) {
}
/** Initialize the PlaybackCardViewModel */
public void init(MediaModels models) {
}
public LiveData<List<MediaSource>> getHistoryList() {
return mHistoryListData;
}
}
رابط کاربری تاریخچه سطح با PlaybackHistoryController
از PlaybackHistoryController
جدید برای کمک به پر کردن داده های سابقه در CarUiRecyclerView
استفاده کنید. سازنده ها و توابع اصلی این کلاس به شرح زیر است. ظرف ارسال شده از برنامه مشتری باید حاوی CarUiRecyclerView
با شناسه history_list
باشد. CarUiRecyclerView
موارد لیست و یک سرصفحه اختیاری را نمایش می دهد. هر دو طرح بندی مورد لیست و هدر را می توان از برنامه مشتری منتقل کرد. اگر Resources.ID_NULL
به عنوان headerResource تنظیم شده باشد، هدر نشان داده نمی شود. پس از اینکه PlaybackCardViewModel
به کنترلر منتقل شد، LiveData<List<MediaSource>>
بازیابی شده از playbackCardViewModel.getHistoryList()
نظارت می کند.
public class PlaybackHistoryController {
public PlaybackHistoryController(
LifecycleOwner lifecycleOwner,
PlaybackCardViewModel playbackCardViewModel,
ViewGroup container,
@LayoutRes int itemResource,
@LayoutRes int headerResource,
int uxrConfigurationId) {
}
/**
* Renders the view.
*/
public void setupView() {
}
}
طرحبندی هر آیتم باید شامل شناسههایی برای Viewهایی باشد که میخواهد نشان دهد که مطابق با موارد استفاده شده در کلاس داخلی ViewHolder
است.
HistoryItemViewHolder(View itemView) {
super(itemView);
mContext = itemView.getContext();
mActiveView = itemView.findViewById(R.id.history_card_container_active);
mInactiveView = itemView.findViewById(R.id.history_card_container_inactive);
mMetadataTitleView = itemView.findViewById(R.id.history_card_title_active);
mAdditionalInfo = itemView.findViewById(R.id.history_card_subtitle_active);
mAppIcon = itemView.findViewById(R.id.history_card_app_thumbnail);
mAlbumArt = itemView.findViewById(R.id.history_card_album_art);
mAppTitleInactive = itemView.findViewById(R.id.history_card_app_title_inactive);
mAppIconInactive = itemView.findViewById(R.id.history_item_app_icon_inactive);
// ...
}
برای نمایش فهرست تاریخچه در یک کارت رسانه ایجاد شده با PlaybackCardController
(یا یک زیر کلاس)، PlaybackHistoryController
را می توان در سازنده PlaybackCardController
ساخت.