Design and Refactoring of Inline Video Playback in Feed Streams
The article describes a modular refactor of Bilibili’s feed‑stream inline video playback, introducing a central ModuleInlineManager, ViewHandler, ViewFetcher, and an InlineController that encapsulate player logic, eliminate duplicated code, simplify maintenance, and enable flexible feature testing across diverse feed pages.
Feed streams are continuous, user‑personalized content flows that combine the notion of "feed" (what you like) with "stream" (the presentation format). They aggregate multiple subscribed sources and present constantly updated information to users.
In this context, "inline playback" refers to video playback directly within the feed list, without opening a separate player page.
Video now accounts for about 80% of internet data, and its share is expected to exceed 82% by 2022. Consequently, many apps embed inline video cards in their feeds, making it a critical component of user interaction.
Bilibili’s homepage recommendation, dynamic list, and search results all support inline playback, each with distinct interaction requirements such as banner priority, auto‑play, danmaku, like buttons, and draggable progress bars. The existing implementation scattered similar logic across multiple ViewControllers and relied on a monolithic checkInlinePlayCard method, leading to duplicated code, numerous flag checks, and fragile maintenance.
The main problems identified were:
Repeated code across different pages and business scenarios.
Intertwined feature flags causing unintended side effects when a single change was made.
Difficulty in extending or testing new playback variations without touching many unrelated modules.
To address these issues, a lightweight architecture was proposed that abstracts the core inline‑playback functionality into reusable components:
ModuleInlineManager : a central manager instantiated by each ViewController to handle all inline‑play events, freeing the controller from detailed playback logic.
ViewHandler : observes the ViewController’s lifecycle, forwards scroll‑stop events to the manager, and proxies delegate methods back to the controller.
ViewFetcher : receives search requests from the manager and locates the most suitable card using a sub‑view traversal and pruning strategy, replacing the previous visible‑cells‑driven approach.
The manager holds two helper objects—ViewHandler and ViewFetcher—and uses configurable strategies and priority tags to decide which card should start playing.
In addition, an InlineController was introduced to encapsulate all player‑related responsibilities for a card. It defines:
DataSource : parameters required to instantiate the player.
CustomLayer : UI overlays such as volume buttons, danmaku toggles, etc., which can be customized per business need.
PlayerCallback : callbacks for playback state changes, exposed as a clean API.
PlayerControl : unified play, pause, replay operations used by the manager or special business scenarios.
This design consolidates previously duplicated logic, provides a strategy‑driven way to handle diverse playback conditions, and offers a clear extension point for future experiments.
With the new architecture, a Feed stream can achieve inline video playback with significantly less code (approximately 2,000 lines reduced to a modular set of components), easier maintenance, and better support for rapid A/B testing.
In summary, the refactoring introduces a modular, lightweight framework for inline video playback in Bilibili’s feed, improving code reuse, reducing technical debt, and preparing the system for future feature growth.
Bilibili Tech
Provides introductions and tutorials on Bilibili-related technologies.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.