https://engineering.fb.com/wp-content/uploads/2018/01/geonnaepxlvrvzagaaaaaacb32jpbj0jaaab.jpg

原文

Improving Android video on News Feed with Litho

随着移动设备上的视频消费快速增长,Facebook 移动工程师面临着高效呈现内容的新挑战。与简单的 UI 元素(如文本和照片)相比,视频需要更多资源。它们使用使 CPU 保持忙碌的解码器;他们分配大量内存进行设置;他们使用更多的网络带宽从服务器下载视频数据。在像 News Feed 这样的可滚动容器中播放视频尤其具有挑战性——设备资源的压力有丢帧的风险,这可能会导致抖动的滚动体验。另外,我们不希望人们等待视频加载,也不希望它在播放过程中缓冲,因此视频播放器需要快速启动并运行流畅。鉴于市场上的设备种类繁多,所有这些挑战都在 Android 上加剧。

我们最近完成了 Android 上的News Feed 迁移,由我们的开源 UI 渲染框架Litho提供支持。Litho 支持异步布局和细粒度回收,这不仅有助于优化 News Feed 以更有效地呈现内容,而且还使我们的代码更健壮且更易于扩展。我们希望为视频带来这些好处,以改善 Facebook 用户和设计新用例的工程师的播放体验。

构建视频 UI 元素比我们处理过的其他 UI 部分更具挑战性。视频组件利用了 Litho 中其他组件不需要的高级功能,并激发了以前不存在的功能。新的 Litho 视频组件引入了多项改进,从 News Feed 的滚动性能到可以轻松重复用于各种视频功能的更灵活的设计。这篇文章介绍了我们在 Android 应用程序中重写视频播放器时面临的挑战,以及 Litho 如何帮助克服这些挑战。

新闻提要中的视频

新闻提要支持多种视频故事类型。有些人的行为和外观与其他人不同。常见的故事类型是视频附件,其中常规视频、Facebook 直播视频、360 度视频、GIF 或其他格式附加到常规帖子。

https://engineering.fb.com/wp-content/uploads/2018/01/GGWEpgGyLKOzdRIHAAAAAADlqB1obj0JAAAB.jpg

其他视频故事类型可以播放生成的视频、赞助消息或短动画。

https://engineering.fb.com/wp-content/uploads/2018/01/GHaunAEvyKTX6KkAAAAAAADMCdsnbj0JAAAC.gif

支持所有这些变体导致代码难以维护和测试。我们的视频附件的主要视频视图被称为VideoAttachmentView。对于一些故事类型,我们必须扩展该视图,以便重用和自定义它以适应设计。在某些情况下,我们无法在派生类中进行所有更改,而必须创建一个单独的视图类,这意味着将公共逻辑移至辅助类。这进一步使代码复杂化。

News Feed 的滚动性能也受到影响。RecyclerView 仅从相同的类类型回收视图,这意味着它不能像SponsoredVideoAttachmentView常规视频附件故事那样回收视图,即使SponsoredVideoAttachmentView扩展VideoAttachmentView. 由于这种低效率,RecyclerView 分配了更多的视图来适应不同的故事类型,从而导致更大的内存占用。此外,分配在视频视图需要出现在屏幕上之前触发,增加了它无法及时准备好并丢失一帧或多帧的机会。即使VideoAttachmentView在新布局中重复使用相同的内容来修改外观VideoAttachmentView,我们需要创建一个新的视图类型。因为我们正在添加另一个层,这也使视图层次结构更深。视图层次结构越深,渲染所需的时间就越长。

设计视频组件

Litho 使用称为“组件”的单元来定义 UI。它支持两种主要类型的组件:MountSpec 和 LayoutSpec。甲MountSpec定义的UI建筑砌块,如文本或图像成分。甲LayoutSpec定义含有一个或多个部件的布局。Litho 中的常见做法是使用组件组合来构建更复杂的组件。LayoutSpec 可以定义包含其他 LayoutSpec 和 MountSpec 组件的布局,而 MountSpec 呈现特定视图或可绘制对象。

视频组件是一个 UI 构建块,这意味着我们需要一个 MountSpec 来定义它。一种选择是创建一个呈现 的 MountSpec VideoAttachmentView,但我们随后需要为其他扩展视图创建一个 MountSpec,例如SponsoredVideoAttachmentView. 虽然这可行,但我们最终会遇到相同的重用和可维护性问题。另一种方法是创建一个 MountSpec 来呈现一个简单的视频视图而不是VideoAttachmentView,并将其添加到一个 LayoutSpec 中,以针对特定的故事类型对其进行调整。下图说明了新组件之间的关系:

https://engineering.fb.com/wp-content/uploads/2018/01/GJi9lgEZTqUOEJMAAAAAAADG1-ogbj0JAAAB.jpg

CoreVideoComponent是一个 MountSpec,具有任何视频故事所需的最少功能。