原文
https://medium.com/pinterest-engineering/managing-videos-on-android-f59da9601d5f
2016年P(guān)interest安卓應用上發(fā)布的視頻模塊,其目標是使得應用能夠提供無(wú)縫的視頻體驗。包括支持在每個(gè)屏幕上同時(shí)播放多個(gè)視頻,并且通過(guò)滾動(dòng)出屏幕自動(dòng)暫停播放的方式來(lái)動(dòng)態(tài)地控制視頻的播放狀態(tài)以及同時(shí)播放的視頻數量。
很快我們發(fā)現其實(shí)需要應對的技術(shù)挑戰有很多,例如:
- 管理當前所有可用視頻的播放狀態(tài)
- 了解視頻在屏幕上的可見(jiàn)率
- 為我們的開(kāi)發(fā)人員提供易于使用的視頻組件
- 隨著(zhù)工作的進(jìn)行,我們逐漸調整視頻架構來(lái)滿(mǎn)足這些需求,下面我們將在最新的視頻模塊中深入探討如何應對這些挑戰。
視頻管理
從更高的層次上來(lái)看,我們需要構建一個(gè)組件,這個(gè)組件需要感知屏幕上所有可用的視頻實(shí)例(即視圖)以及其相關(guān)的surfaces(即視頻片段)。管理surfaces對于監控應用于surfaces的子對象的生命周期狀態(tài)(即onStart()等)至關(guān)重要,并且避免在使用者層上添加過(guò)多代碼來(lái)將最新?tīng)顟B(tài)更改應用到視圖。
為了跟蹤這些關(guān)鍵的生命周期事件,Android框架向我們提供了屏幕顯示內容的當前狀態(tài)以及視覺(jué)上影響我們應用程序的任何更改。我們監測的關(guān)鍵生命周期事件是UI附件調用(例如onAttachedToWindow())以及主機屏幕何時(shí)更改其顯示狀態(tài)(例如onPause()等)。
使用這些回調方法,我們嘗試記錄已提供有效視頻URL的所有視頻。這將為我們提供當前范圍內可用的視頻的初始列表。
在視頻框架的第一個(gè)迭代中,我們依靠客戶(hù)端代碼本身調用這些調用,但是我們發(fā)現這是不可擴展的。因為它在構建視頻功能時(shí)增加了更多的復雜性。取而代之的方法是,我們通過(guò)構建需要傳入基礎視頻組件的方法,提取了在VideoManager之后注冊視頻的回調方法。從那里,VideoManager將在幕后進(jìn)行適當的計算。由于它現在才可以“開(kāi)箱即用”地工作,因此消除了觀(guān)眾對視頻記錄過(guò)程已經(jīng)具有預定義知識的需求。
改進(jìn)前
// FooBarFragment.class for FooBar feature
override fun onResume() {
super.onResume()
// Required by consumers to implement
videoView?.apply {
viewability = Viewability.FullyVisible
onActivate()
onViewCompletelyVisible()
}
}
override fun onPause() {
// Required by consumers to implement
videoView?.apply {
viewability = Viewability.NotVisible
onDeactivate()
}
super.onPause()
}
改進(jìn)后
// BaseFragment.class implemented by all screens
override fun onResume() {
super.onResume()
videoManager.onResume(this)
}
override fun onPause() {
videoManager.onPause(this)
super.onPause()
}
// VideoManager.class internally
override fun onResume(videoSurface: VideoViewSurface) {
videoSurface.videoViews.forEach {
registerVideo(it)
}
}
override fun onPause(videoSurface: VideoViewSurface) {
videoSurface.videoViews.forEach {
unregisterVideo(it)
}
}
保留這個(gè)視頻列表讓我們可以根據應用程序的當前可見(jiàn)性來(lái)動(dòng)態(tài)地設置播放狀態(tài)。同時(shí)這個(gè)方法還提供了基于在視頻記錄時(shí)傳遞的某些元數據屬性動(dòng)態(tài)更改之類(lèi)其他功能的靈活性。
例如,我們可能希望所有視頻廣告都自動(dòng)播放,但僅限于在同一片段上自動(dòng)播放1個(gè)有機視頻(即創(chuàng )作者生成的內容)。通過(guò)檢查在單個(gè)視頻上記錄的元數據,我們可以將這些限制應用于UI層。
我們還提取了所有Pinterest特定的分析代碼,用以來(lái)聚焦在視頻管理器(管理和播放視頻)功能上,同時(shí)讓這個(gè)管理組件和應用程序之間保持獨立。
計算可視性
可視性定義為在屏幕上顯示的UI組件的可見(jiàn)區域的百分比。此度量對于我們了解當前顯示給用戶(hù)的內容至關(guān)重要。有了這些信息,我們就能為合作伙伴收集有關(guān)其內容參與度的信息。
在常見(jiàn)情況下,由于VideoManager保留對所有活動(dòng)視頻的引用,因此我們可以跟蹤視圖的確切坐標(即getLocationInWindow())和設備的屏幕尺寸(以像素為單位)(請參見(jiàn)DisplayMetrics),以推斷其在屏幕上的可見(jiàn)性。
我們還通過(guò)以下方式處理重疊的UI組件:
向消費者提供包括一系列``障礙物’'視圖的選項,這些視圖可能會(huì )覆蓋我們的基礎視頻(例如工具欄,浮動(dòng)按鈕等)
顯示彈出窗口的回調(即onWindowFocusChanged())屏幕滾動(dòng)組件或UI組件不在屏幕上(請參閱RecyclerView監聽(tīng)器)
屏幕上顯示視頻表面時(shí)的其他回調(即onResume()等)
為開(kāi)發(fā)人員打造的內容
雖然我們希望減少開(kāi)發(fā)人員面臨的視頻管理復雜性,但是這其中最大的困難就是采用新的視頻界面。因此,我們都抽象出了視頻設置的復雜性以及Google PlayerView提供的UI組件的使用:
改進(jìn)前
// FooBar video feature, requires custom FooBarVideoView.class of 100+ lines
object : FooBarVideoView(
context, // application context
analytics, // Analytics object
url, // video url
uid, // unique ID
false // isAd flag
) {
// configuration flag for custom setup (mute, autoplay, controller, etc.)
override val videoConfiguration = VideoConfiguration.FOO_BAR
}.apply {
shouldLoop = true
videoAspectRatio = aspectRatio
render(videoMetaData) // loads video, videoMetaData contains: url, isAd, uid
}
改進(jìn)后
// Foobar video feature, no custom class required just set flags
PinterestVideoView(context).apply {
// Optional params for setup/customization
this.analytics = pinterestAnalytics
this.mute = false
this.autoPlay = true
this.alwaysAutoplay = true
this.alwaysPlay = true
this.showMute = true
this.looping = true
this.bufferingRule = SHOW_BUFFERING_ALWAYS
}.apply {
render(videoMetaData) // loads video, videoMetaData contains: url, isAd, uid
}
視頻基礎架構的另一個(gè)復雜性是實(shí)際的VideoManager體系結構本身。在我們的重寫(xiě)中,我們將大多數舊組件合并為僅支持正常運行的VideoManager的核心部分。
改進(jìn)前

改進(jìn)后

我們新的VideoManager體系結構為事件和組件之間的相互關(guān)系提供了清晰的層次結構。這不僅在紙面上看起來(lái)不錯,而且僅重構一項就刪除了約4,500行代碼(不到原始實(shí)現大小的1/3)
展望
建立適當的“視頻管理”是一個(gè)漫長(cháng)而艱巨的過(guò)程,但是多年來(lái),我們已經(jīng)構建了一些真正經(jīng)過(guò)改進(jìn)的東西,以幫助簡(jiǎn)化我們的開(kāi)發(fā)流程和Pinner體驗。將來(lái),我們希望開(kāi)源我們的工作,以便其他開(kāi)發(fā)人員可以為正在進(jìn)行的處理動(dòng)態(tài)視頻回放做出貢獻。我們將繼續迭代我們的視頻客戶(hù)端架構,以應對新的挑戰,以期為Pinners和開(kāi)發(fā)人員提供令人愉悅的視頻體驗。來(lái)源:LiveVideoStack