Medya kartı, başlık ve albüm kapağı gibi medya meta verilerini gösteren, Oynat, Duraklat ve Atla gibi oynatma denetimlerinin yanı sıra üçüncü taraf medya uygulaması tarafından sağlanan özel işlemleri gösteren bağımsız bir ViewGroup'dur. Medya kartı, oynatma listesi gibi bir medya öğesi sırasını da gösterebilir.
Şekil 1. Medya kartı örnek uygulamaları.
Medya kartları AAOS'te nasıl uygulanır?
Medya bilgilerini gösteren ViewGroup'lar, ViewGroup'u doldurmak için car-media-common
kitaplık verileri modelinden (PlaybackViewModel
) gelen LiveData güncellemelerini izler. Her LiveData güncellemesi, MediaItemMetadata
, PlaybackStateWrapper
ve MediaSource
gibi değişen bir medya bilgisi alt kümesine karşılık gelir.
Bu yaklaşım, yinelenen koda yol açtığından (her istemci uygulaması, her LiveData parçasına gözlemci ekler ve güncellenen veriler birçok benzer görünüme atanır) PlaybackCardController
'i oluşturduk.
PlaybackCardController
PlaybackCardController
, medya kartı oluşturmaya yardımcı olmak için car-media-common
kitaplığına eklendi. Bu, bir ViewGroup (mView
), PlaybackViewModel (mDataModel
), PlaybackCardViewModel (mViewModel
) ve MediaItemsRepository
örneği (mItemsRepository
) ile oluşturulan herkese açık bir sınıftır.
setupController
işlevinde, ViewGroup, mView.findViewById(R.id.xxx)
ile kimliğe göre belirli görünümler için ayrıştırılır ve korunan View nesnelerine atanır.
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);
// ...
}
PlaybackViewModel
kaynağından gelen her LiveData güncellemesi, korumalı bir yöntemle gözlemlenir ve alınan verilerle alakalı Görünümlerle etkileşim gerçekleştirir. Örneğin, MediaItemMetadata
'teki bir gözlemci, mTitle
TextView
'de başlığı ayarlar ve MediaItemMetadata.ArtworkRef
'ı albüm resmi ImageBinder
mAlbumArtBinder
'e iletir. Meta veriler null ise Görüntüleme Sayısı gizlenir. Denetleyicinin alt sınıfları gerekirse bu mantığı geçersiz kılabilir.
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'ı genişletin
Medya kartı oluşturmak isteyen istemci uygulamaları, her LiveData güncellemesinde ele almak istedikleri ek bir özellik varsa PlaybackCardController
sınıfını genişletmelidir. AAOS'teki mevcut istemciler bu kalıbı izler.
Öncelikle, MediaCardController
gibi bir PlaybackCardController
alt sınıfı oluşturulmalıdır. Ardından MediaCardController
, PlaybackCardController
sınıfını genişleten statik bir iç Builder sınıfı eklemelidir.
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 veya alt sınıfını örneklendirin
LiveData gözlemcileri için bir LifecycleOwner'a sahip olmak amacıyla Controller sınıfı bir Fragment veya Activity'den oluşturulmalıdır.
mMediaCardController = (MediaCardController) new MediaCardController.Builder()
.setModels(mViewModel.getPlaybackViewModel(),
mViewModel,
mViewModel.getMediaItemsRepository())
.setViewGroup((ViewGroup) view)
.build();
mViewModel
, PlaybackCardViewModel
(veya alt sınıf) örneğidir.
Durumu Kaydetme İçin PlaybackCardViewModel
PlaybackCardViewModel
, bir yapılandırma değişikliği (ör. kullanıcı bir tünelden geçerken açık temadan koyu temaya geçiş) olduğunda medya kartının içeriğini yeniden oluşturmak için kullanılması gereken, bir Fragment veya Activity'ye bağlı, durum kaydeden bir ViewModel'dir. Varsayılan PlaybackCardViewModel
, oynatılmak üzere MediaModel
örneklerini saklar. Bu örneklerden PlaybackViewModel
ve MediaItemsRepository
alınabilir. Sağlanan alıcı ve ayarlayıcılar aracılığıyla kuyruğun, geçmişin ve taşma menüsünün durumunu izlemek için PlaybackCardViewModel
öğesini kullanın.
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;
}
}
Daha fazla eyaletin izlenmesi gerekiyorsa bu sınıf genişletilebilir.
Medya kartında sıra gösterme
PlaybackViewModel
, MediaSource'un sırayı destekleyip desteklemediğini algılamak ve sıradaki MediaItemMetadata
nesnelerinin listesini almak için LiveData API'leri sağlar. Bu API'ler, bir RecyclerView
nesnesini doğrudan sıra bilgileriyle doldurmak için kullanılabilir olsa da bu işlemi kolaylaştırmak amacıyla car-media-common
kitaplığına bir PlaybackQueueController
sınıfı eklenmiştir. CarUiRecyclerView
içindeki her öğenin düzeni, isteğe bağlı bir başlık düzeni olarak istemci uygulaması tarafından da belirtilir. İstemci uygulaması, özel UXR kısıtlamalarıyla sürüş durumunda kuyrukta gösterilen öğe sayısını da sınırlayabilir.
PlaybackQueueController
kurucusu ve ayarlayıcıları aşağıdaki örnekte gösterilmektedir. queueResource
ve headerResource
düzen kaynakları, önceki durumda kapsayıcıda id queue_list
içeren bir CarUiRecyclerView
varsa ve son durumda kuyrukta bir başlık yoksa Resources.ID_NULL
olarak iletilebilir.
/**
* 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;
}
Her sıra öğesinin düzeni, göstermek istediği ve QueueViewHolder
iç sınıfında kullanılanlara karşılık gelen Görünümlerin kimliklerini içermelidir.
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
(veya alt sınıf) ile oluşturulan bir medya kartında sıra göstermek için PlaybackQueueController
, PlaybackCardController
yapıcısında sırasıyla PlaybackViewModel
ve MediaItemsRepository
örnekleri için mDataModel
ve mItemsRepository
kullanılarak oluşturulabilir.
Daha önce oynatılan MediaSources'ın geçmişini gösterme
Bu bölümde, daha önce oynatılan medya kaynaklarının geçmişini nasıl göstereceğinizi ve bu geçmişi nasıl bulacağınızı öğreneceksiniz.
PlaybackCardViewModel API ile geçmiş listesini alma
PlaybackCardViewModel
, medya geçmişi listesini almak için getHistoryList()
adlı bir LiveData API sağlar. Daha önce oynatılan MediaSource öğelerinin listesini içeren bir LiveData döndürür. Bu veriler, bir CarUiRecyclerView
nesnesini doldurmak için kullanılabilir. PlaybackQueueController
'e benzer şekilde, işlemi kolaylaştırmak için car-media-common
kitaplığına PlaybackHistoryController
adlı bir sınıf eklendi.
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 ile geçmiş kullanıcı arayüzü
Geçmiş verilerini bir CarUiRecyclerView
ile doldurmak için yeni PlaybackHistoryController
'ü kullanın. Bu sınıfın kurucuları ve ana işlevleri aşağıdaki gibidir. İstemci uygulamasından iletilen kapsayıcı, history_list
kimlikli bir CarUiRecyclerView
içermelidir. CarUiRecyclerView
liste öğelerini ve isteğe bağlı bir üstbilgi gösterir. Hem liste öğesi hem de başlık için düzenler istemci uygulamasından iletilebilir. Resources.ID_NULL
, headerResource olarak ayarlanırsa başlık gösterilmez. PlaybackCardViewModel
, kontrolöre aktarıldıktan sonra playbackCardViewModel.getHistoryList()
'den alınan LiveData<List<MediaSource>>
'ı izler.
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() {
}
}
Her öğenin düzeni, göstermek istediği görünümlerin kimliklerini içermelidir. Bu kimlikler, ViewHolder
iç sınıfında kullanılanlara karşılık gelmelidir.
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
(veya alt sınıf) ile oluşturulan bir medya kartında geçmiş listesi göstermek için PlaybackHistoryController
, PlaybackCardController
'ün kurucusunda oluşturulabilir.