Medya kartı, başlık ve albüm resmi gibi medya meta verilerini gösteren ve Oynat, Duraklat, Atla gibi oynatma kontrollerinin yanı sıra üçüncü taraf medya uygulaması tarafından sağlanan özel işlemleri de sunan bağımsız bir ViewGroup'tur. Medya kartı, oynatma listesi gibi medya öğelerinin sırasını da gösterebilir.
1. şekil. Medya Kartı örnek uygulamaları.
Medya kartları AAOS'te nasıl uygulanır?
Medya bilgilerini gösteren ViewGroups, ViewGroup'u doldurmak için car-media-common
kitaplığındaki data modelinden (PlaybackViewModel
) gelen LiveData güncellemelerini izler. Her LiveData güncellemesi, değişen medya bilgilerinin bir alt kümesine karşılık gelir. Örneğin, MediaItemMetadata
, PlaybackStateWrapper
ve MediaSource
.
Bu yaklaşım, tekrarlanan koda yol açtığı için (her istemci uygulaması, her LiveData parçasına Gözlemciler ekler ve birçok benzer Görünüme güncellenen veriler atanır) PlaybackCardController
oluşturduk.
PlaybackCardController
Medya kartı oluşturmaya yardımcı olmak için PlaybackCardController
, car-media-common
kitaplığına eklendi. Bu, ViewGroup (mView
), PlaybackViewModel (mDataModel
), PlaybackCardViewModel (mViewModel
) ve MediaItemsRepository
örneği (mItemsRepository
) ile oluşturulmuş herkese açık bir sınıftır.
setupController
işlevinde, ViewGroup, mView.findViewById(R.id.xxx)
ile belirli görünümler için kimliğe göre ayrıştırılır ve korumalı 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öntemde gözlemlenir ve alınan verilerle ilgili Görünümlerle etkileşimde bulunur. Örneğin, MediaItemMetadata
üzerindeki bir gözlemci, mTitle
TextView
üzerinde başlığı ayarlar ve MediaItemMetadata.ArtworkRef
öğesini albüm kapağına ImageBinder
mAlbumArtBinder
iletir. Meta veriler null ise görünümler gizlenir. Denetleyici'nin 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);
}
}
Extend the PlaybackCardController
Medya kartı oluşturmak isteyen istemci uygulamaları, her LiveData güncellemesinde işlemek istedikleri ek özellikler varsa PlaybackCardController
öğesini genişletmelidir. AAOS'taki mevcut istemciler bu kalıbı izler.
Öncelikle PlaybackCardController
gibi bir alt sınıf oluşturulmalıdır.
MediaCardController
. 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 bir alt sınıfı başlatın.
Denetleyici sınıfı, LiveData gözlemcileri için bir LifecycleOwner'a sahip olmak üzere bir Parçadan veya Etkinlikten başlatılmalı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 Kaydetmek İçin PlaybackCardViewModel
PlaybackCardViewModel
, bir Fragment veya Activity'ye bağlı, durumu kaydeden bir ViewModel'dir. Yapılandırma değişikliği (ör. kullanıcı tünelden geçerken açık temadan koyu temaya geçiş) meydana gelirse medya kartının içeriğini yeniden oluşturmak için kullanılmalıdır. Varsayılan PlaybackCardViewModel
, oynatma için MediaModel
örneklerinin depolanmasını sağlar. Bu örneklerden PlaybackViewModel
ve MediaItemsRepository
alınabilir. Kuyruğun durumunu, geçmişini ve taşma menüsünü sağlanan getter'lar ve setter'lar aracılığıyla izlemek için PlaybackCardViewModel
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;
}
}
Ek eyaletlerin izlenmesi gerekiyorsa bu sınıf genişletilebilir.
Medya kartında sırayı gösterme
PlaybackViewModel
, MediaSource'un bir kuyruğu destekleyip desteklemediğini algılamak ve kuyruktaki MediaItemMetadata
nesnelerinin listesini almak için LiveData API'leri sağlar. Bu API'ler, RecyclerView
nesnesini sıra bilgileriyle doldurmak için doğrudan kullanılabilse de bu süreci kolaylaştırmak amacıyla car-media-common
kitaplığına bir PlaybackQueueController
sınıfı eklenmiştir. CarUiRecyclerView
içindeki her öğenin düzeni, istemci uygulaması ve isteğe bağlı bir başlık düzeni tarafından belirtilir. İstemci uygulaması, sürüş durumunda kuyrukta gösterilen öğe sayısını özel UXR kısıtlamalarıyla sınırlamayı da seçebilir.
PlaybackQueueController
oluşturucusu ve ayarlayıcıları aşağıdaki örnekte gösterilmektedir. queueResource
ve headerResource
düzen kaynakları, Resources.ID_NULL
olarak iletilebilir. İlk durumda kapsayıcı zaten id queue_list
ile CarUiRecyclerView
içeriyorsa, ikinci durumda ise kuyrukta başlık yoksa bu işlem yapılabilir.
/**
* 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 kuyruk öğesinin düzeni, QueueViewHolder
iç sınıfında kullanılanlarla eşleşen ve göstermek istediği 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
ile oluşturulan bir medya kartında sıra göstermek için PlaybackCardController
, PlaybackViewModel
ve MediaItemsRepository
örnekleri için sırasıyla mDataModel
ve mItemsRepository
kullanılarak PlaybackCardController
oluşturucusunda oluşturulabilir.PlaybackQueueController
Daha önce oynatılan MediaSource'ların geçmişini göster
Bu bölümde, daha önce oynatılan medya kaynaklarının geçmişini nasıl göstereceğinizi ve ortaya çıkaracağı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ılmış MediaSource'ların listesini içeren bir LiveData döndürür. Bu veriler, CarUiRecyclerView
nesnesini doldurmak için kullanılabilir. PlaybackQueueController
'ya benzer şekilde, süreci 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 Surface geçmişi kullanıcı arayüzü
Geçmiş verilerini CarUiRecyclerView
ile doldurmak için yeni PlaybackHistoryController
özelliğini kullanın. Bu sınıfın oluşturucuları ve ana işlevleri aşağıda verilmiştir. İstemci uygulamasından geçirilen kapsayıcı, kimliği history_list
olan bir CarUiRecyclerView
içermelidir. CarUiRecyclerView
liste öğelerini ve isteğe bağlı bir başlığı gösterir. Hem liste öğesi hem de başlık düzenleri istemci uygulamasından geçirilebilir. Resources.ID_NULL
, headerResource olarak ayarlanırsa başlık gösterilmez. PlaybackCardViewModel
denetleyiciye iletildikten sonra playbackCardViewModel.getHistoryList()
kaynağından alınan LiveData<List<MediaSource>>
izlenir.
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, ViewHolder
iç sınıfında kullanılanlarla eşleşen ve göstermek istediği görünümlerin kimliklerini içermelidir.
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 bir alt sınıf) ile oluşturulan bir medya kartında geçmiş listesi göstermek için PlaybackHistoryController
, PlaybackCardController
oluşturucusunda oluşturulabilir.